1 /*
2 * Tvheadend - Linux DVB satconf
3 *
4 * Copyright (C) 2013 Adam Sutton
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "tvheadend.h"
21 #include "linuxdvb_private.h"
22 #include "settings.h"
23
24 #include <sys/ioctl.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <math.h>
29 #include <fcntl.h>
30 #include <assert.h>
31 #include <linux/dvb/dmx.h>
32 #include <linux/dvb/frontend.h>
33
34 static struct linuxdvb_satconf_type *
35 linuxdvb_satconf_type_find ( const char *type );
36
37 struct linuxdvb_satconf_type {
38 int enable;
39 int ports;
40 const char *type;
41 const char *name;
42 const idclass_t *idc;
43 };
44
45 /* **************************************************************************
46 * Types
47 * *************************************************************************/
48
49 static const void *
linuxdvb_satconf_class_active_get(void * obj)50 linuxdvb_satconf_class_active_get ( void *obj )
51 {
52 static int active;
53 linuxdvb_satconf_t *ls = obj;
54 linuxdvb_satconf_ele_t *lse;
55 active = 0;
56 if (*(int *)linuxdvb_frontend_class_active_get(ls->ls_frontend)) {
57 TAILQ_FOREACH(lse, &ls->ls_elements, lse_link) {
58 if (lse->lse_enabled) {
59 active = 1;
60 break;
61 }
62 }
63 }
64 return &active;
65 }
66
67 static linuxdvb_satconf_ele_t *
linuxdvb_satconf_class_find_ele(linuxdvb_satconf_t * ls,int idx)68 linuxdvb_satconf_class_find_ele( linuxdvb_satconf_t *ls, int idx )
69 {
70 int i = 0;
71 linuxdvb_satconf_ele_t *lse;
72 TAILQ_FOREACH(lse, &ls->ls_elements, lse_link) {
73 if (i == idx) break;
74 i++;
75 }
76 return lse;
77 }
78
79 static const void *
linuxdvb_satconf_class_network_get(linuxdvb_satconf_t * ls,int idx)80 linuxdvb_satconf_class_network_get( linuxdvb_satconf_t *ls, int idx )
81 {
82 linuxdvb_satconf_ele_t *lse = linuxdvb_satconf_class_find_ele(ls, idx);
83 if (lse)
84 return idnode_set_as_htsmsg(lse->lse_networks);
85 return NULL;
86 }
87
88 static int
89 linuxdvb_satconf_ele_class_network_set( void *o, const void *p );
90
91 static int
linuxdvb_satconf_class_network_set(linuxdvb_satconf_t * ls,int idx,const void * networks)92 linuxdvb_satconf_class_network_set
93 ( linuxdvb_satconf_t *ls, int idx, const void *networks )
94 {
95 linuxdvb_satconf_ele_t *lse = linuxdvb_satconf_class_find_ele(ls, idx);
96 if (lse)
97 return linuxdvb_satconf_ele_class_network_set(lse, networks);
98 return 0;
99 }
100
101 static htsmsg_t *
linuxdvb_satconf_class_network_enum(void * o,const char * lang)102 linuxdvb_satconf_class_network_enum( void *o, const char *lang )
103 {
104 htsmsg_t *m = htsmsg_create_map();
105 htsmsg_t *p = htsmsg_create_map();
106 htsmsg_add_str(m, "type", "api");
107 htsmsg_add_str(m, "uri", "idnode/load");
108 htsmsg_add_str(m, "event", "mpegts_network");
109 htsmsg_add_u32(p, "enum", 1);
110 htsmsg_add_str(p, "class", dvb_network_dvbs_class.ic_class);
111 htsmsg_add_msg(m, "params", p);
112
113 return m;
114 }
115
116 static char *
117 linuxdvb_satconf_ele_class_network_rend( void *o, const char *lang );
118
119 static char *
linuxdvb_satconf_class_network_rend(linuxdvb_satconf_t * ls,int idx,const char * lang)120 linuxdvb_satconf_class_network_rend( linuxdvb_satconf_t *ls, int idx, const char *lang )
121 {
122 linuxdvb_satconf_ele_t *lse = linuxdvb_satconf_class_find_ele(ls, idx);
123 if (lse)
124 return linuxdvb_satconf_ele_class_network_rend(lse, lang);
125 return NULL;
126 }
127
128 #define linuxdvb_satconf_class_network_getset(x)\
129 static int \
130 linuxdvb_satconf_class_network_set##x ( void *o, const void *v )\
131 {\
132 return linuxdvb_satconf_class_network_set(o, x, (void*)v);\
133 }\
134 static const void * \
135 linuxdvb_satconf_class_network_get##x ( void *o )\
136 {\
137 return linuxdvb_satconf_class_network_get(o, x);\
138 }\
139 static char * \
140 linuxdvb_satconf_class_network_rend##x ( void *o, const char *lang )\
141 {\
142 return linuxdvb_satconf_class_network_rend(o, x, lang);\
143 }
144
145 linuxdvb_satconf_class_network_getset(0);
146 linuxdvb_satconf_class_network_getset(1);
147 linuxdvb_satconf_class_network_getset(2);
148 linuxdvb_satconf_class_network_getset(3);
149
150 static const char *
linuxdvb_satconf_class_get_title(idnode_t * p,const char * lang)151 linuxdvb_satconf_class_get_title ( idnode_t *p, const char *lang )
152 {
153 linuxdvb_satconf_t *ls = (linuxdvb_satconf_t*)p;
154 struct linuxdvb_satconf_type *lst =
155 linuxdvb_satconf_type_find(ls->ls_type);
156 return lst ? lst->name : ls->ls_type;
157 }
158
159 static void
linuxdvb_satconf_class_changed(idnode_t * s)160 linuxdvb_satconf_class_changed ( idnode_t *s )
161 {
162 linuxdvb_satconf_t *ls = (linuxdvb_satconf_t*)s;
163 linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)ls->ls_frontend;
164 linuxdvb_adapter_t *la = lfe->lfe_adapter;
165 linuxdvb_adapter_changed(la);
166 }
167
168 static const void *
linuxdvb_satconf_class_orbitalpos_get(void * p)169 linuxdvb_satconf_class_orbitalpos_get ( void *p )
170 {
171 static int n;
172 linuxdvb_satconf_t *ls = p;
173 linuxdvb_satconf_ele_t *lse;
174 n = 0;
175 TAILQ_FOREACH(lse, &ls->ls_elements, lse_link)
176 n++;
177 return &n;
178 }
179
180 static int
linuxdvb_satconf_class_orbitalpos_set(void * p,const void * v)181 linuxdvb_satconf_class_orbitalpos_set
182 ( void *p, const void *v )
183 {
184 linuxdvb_satconf_ele_t *lse;
185 linuxdvb_satconf_t *ls = p;
186 int c = *(int*)linuxdvb_satconf_class_orbitalpos_get(p);
187 int n = *(int*)v;
188 char buf[22];
189
190 if (n == c)
191 return 0;
192
193 /* Add */
194 if (n > c) {
195 while (c < n) {
196 lse = linuxdvb_satconf_ele_create0(NULL, NULL, ls);
197 if (lse->lse_name == NULL) {
198 snprintf(buf, sizeof(buf), "Position #%i", c + 1);
199 lse->lse_name = strdup(buf);
200 }
201 c++;
202 }
203
204 /* Remove */
205 } else {
206 while (c > n) {
207 lse = TAILQ_LAST(&ls->ls_elements, linuxdvb_satconf_ele_list);
208 linuxdvb_satconf_ele_destroy(lse);
209 c--;
210 }
211 }
212
213 return 1;
214 }
215
216 static idnode_set_t *
linuxdvb_satconf_class_get_childs(idnode_t * o)217 linuxdvb_satconf_class_get_childs ( idnode_t *o )
218 {
219 linuxdvb_satconf_t *ls = (linuxdvb_satconf_t*)o;
220 linuxdvb_satconf_ele_t *lse;
221 idnode_set_t *is = idnode_set_create(0);
222 TAILQ_FOREACH(lse, &ls->ls_elements, lse_link)
223 idnode_set_add(is, &lse->lse_id, NULL, NULL);
224 return is;
225 }
226
227 static htsmsg_t *
linuxdvb_satconf_class_highvol_list(void * o,const char * lang)228 linuxdvb_satconf_class_highvol_list ( void *o, const char *lang )
229 {
230 static const struct strtab tab[] = {
231 { N_("Do not set"), 0 },
232 { N_("Normal"), 1 },
233 { N_("Higher"), 2 }
234 };
235 return strtab2htsmsg(tab, 1, lang);
236 }
237
238 /*
239 * Generic satconf
240 */
241
242 CLASS_DOC(linuxdvb_satconf) /* Referenced by multiple classes. */
243
244 const idclass_t linuxdvb_satconf_class =
245 {
246 .ic_class = "linuxdvb_satconf",
247 .ic_caption = N_("DVB-S Satellite Configuration"),
248 .ic_event = "linuxdvb_satconf",
249 .ic_get_title = linuxdvb_satconf_class_get_title,
250 .ic_doc = tvh_doc_linuxdvb_satconf_class,
251 .ic_changed = linuxdvb_satconf_class_changed,
252 .ic_properties = (const property_t[]) {
253 {
254 .type = PT_BOOL,
255 .id = "active",
256 .name = N_("Active"),
257 .opts = PO_RDONLY | PO_NOSAVE | PO_NOUI,
258 .get = linuxdvb_satconf_class_active_get,
259 },
260 {
261 .type = PT_BOOL,
262 .id = "early_tune",
263 .name = N_("Tune before DiseqC"),
264 .desc = N_("One tune request (setup) is sent before the "
265 "DiseqC sequence (voltage, tone settings). "
266 "Some linux drivers require this procedure."),
267 .off = offsetof(linuxdvb_satconf_t, ls_early_tune),
268 .opts = PO_ADVANCED,
269 .def.i = 1
270 },
271 {
272 .type = PT_INT,
273 .id = "diseqc_repeats",
274 .name = N_("DiseqC repeats"),
275 .desc = N_("Number of repeats for the DiseqC commands "
276 "(default is zero - no DiseqC repeats). "
277 "Note: this represents the number of repeats, not "
278 "the number of requests - so 0 means 'send once: "
279 "don't repeat', 1 means 'send twice: send once, "
280 "then send one repeat', etc."),
281 .off = offsetof(linuxdvb_satconf_t, ls_diseqc_repeats),
282 .opts = PO_ADVANCED,
283 .def.i = 0
284 },
285 {
286 .type = PT_BOOL,
287 .id = "diseqc_full",
288 .name = N_("Full DiseqC"),
289 .desc = N_("Always send the whole DiseqC sequence including "
290 "LNB setup (voltage, tone). If this is not "
291 "checked, only changed settings are sent, which "
292 "may cause issues with some drivers. If the tuning "
293 "is not reliable, try activating this option."),
294 .off = offsetof(linuxdvb_satconf_t, ls_diseqc_full),
295 .opts = PO_ADVANCED,
296 .def.i = 1
297 },
298 {
299 .type = PT_BOOL,
300 .id = "lnb_poweroff",
301 .name = N_("Turn off LNB when idle"),
302 .desc = N_("Switch off the power to the LNB when idle. Note: "
303 "this may cause interference with other devices "
304 "when the LNB is powered back up."),
305 .off = offsetof(linuxdvb_satconf_t, ls_lnb_poweroff),
306 .opts = PO_ADVANCED,
307 .def.i = 1
308 },
309 {
310 .type = PT_INT,
311 .id = "lnb_highvol",
312 .name = N_("Higher LNB voltage"),
313 .desc = N_("Some DVB devices have an optional ioctl that allows "
314 "changing between normal voltage for LNB (13V/18V) to "
315 "a higher voltage mode (usually, 14V/19V), meant to "
316 "compensate for voltage loss on long cabling. "
317 "Without that, it is not possible to properly switch "
318 "the polarization."),
319 .list = linuxdvb_satconf_class_highvol_list,
320 .off = offsetof(linuxdvb_satconf_t, ls_lnb_highvol),
321 .opts = PO_ADVANCED,
322 .def.i = 1
323 },
324 {}
325 }
326 };
327
328 /*
329 * Simple LNB only
330 */
331 const idclass_t linuxdvb_satconf_lnbonly_class =
332 {
333 .ic_super = &linuxdvb_satconf_class,
334 .ic_class = "linuxdvb_satconf_lnbonly",
335 .ic_doc = tvh_doc_linuxdvb_satconf_class,
336 .ic_caption = N_("TV Adapters - SatConfig - Universal LNB (Simple)"),
337 .ic_properties = (const property_t[]) {
338 {
339 .type = PT_STR,
340 .id = "networks",
341 .name = N_("Networks"),
342 .desc = N_("The networks assigned to the device."),
343 .islist = 1,
344 .get = linuxdvb_satconf_class_network_get0,
345 .set = linuxdvb_satconf_class_network_set0,
346 .list = linuxdvb_satconf_class_network_enum,
347 .rend = linuxdvb_satconf_class_network_rend0,
348 .opts = PO_NOSAVE,
349 },
350 {}
351 }
352 };
353
354 /*
355 * 2 port switch
356 */
357 const idclass_t linuxdvb_satconf_2port_class =
358 {
359 .ic_super = &linuxdvb_satconf_class,
360 .ic_class = "linuxdvb_satconf_2port",
361 .ic_doc = tvh_doc_linuxdvb_satconf_class,
362 .ic_caption = N_("TV Adapters - SatConfig - Tone Burst/2 Port"),
363 .ic_properties = (const property_t[]) {
364 {
365 .type = PT_STR,
366 .id = "network_a",
367 .name = N_("A"),
368 .desc = N_("Network for port A."),
369 .islist = 1,
370 .get = linuxdvb_satconf_class_network_get0,
371 .set = linuxdvb_satconf_class_network_set0,
372 .list = linuxdvb_satconf_class_network_enum,
373 .rend = linuxdvb_satconf_class_network_rend0,
374 .opts = PO_NOSAVE,
375 },
376 {
377 .type = PT_STR,
378 .id = "network_b",
379 .name = N_("B"),
380 .desc = N_("Network for port B."),
381 .islist = 1,
382 .get = linuxdvb_satconf_class_network_get1,
383 .set = linuxdvb_satconf_class_network_set1,
384 .list = linuxdvb_satconf_class_network_enum,
385 .rend = linuxdvb_satconf_class_network_rend1,
386 .opts = PO_NOSAVE,
387 },
388 {}
389 }
390 };
391
392 /*
393 * 4 port switch
394 */
395 const idclass_t linuxdvb_satconf_4port_class =
396 {
397 .ic_super = &linuxdvb_satconf_class,
398 .ic_class = "linuxdvb_satconf_4port",
399 .ic_doc = tvh_doc_linuxdvb_satconf_class,
400 .ic_caption = N_("TV Adapters - SatConfig - 4-Port"),
401 .ic_properties = (const property_t[]) {
402 {
403 .type = PT_STR,
404 .id = "network_aa",
405 .name = N_("AA"),
406 .desc = N_("Network for port AA."),
407 .islist = 1,
408 .get = linuxdvb_satconf_class_network_get0,
409 .set = linuxdvb_satconf_class_network_set0,
410 .list = linuxdvb_satconf_class_network_enum,
411 .rend = linuxdvb_satconf_class_network_rend0,
412 .opts = PO_NOSAVE,
413 },
414 {
415 .type = PT_STR,
416 .id = "network_ab",
417 .name = N_("AB"),
418 .desc = N_("Network for port AB."),
419 .islist = 1,
420 .get = linuxdvb_satconf_class_network_get1,
421 .set = linuxdvb_satconf_class_network_set1,
422 .list = linuxdvb_satconf_class_network_enum,
423 .rend = linuxdvb_satconf_class_network_rend1,
424 .opts = PO_NOSAVE,
425 },
426 {
427 .type = PT_STR,
428 .id = "network_ba",
429 .name = N_("BA"),
430 .desc = N_("Network for port BA."),
431 .islist = 1,
432 .get = linuxdvb_satconf_class_network_get2,
433 .set = linuxdvb_satconf_class_network_set2,
434 .list = linuxdvb_satconf_class_network_enum,
435 .rend = linuxdvb_satconf_class_network_rend2,
436 .opts = PO_NOSAVE,
437 },
438 {
439 .type = PT_STR,
440 .id = "network_bb",
441 .name = N_("BB"),
442 .desc = N_("Network for port BB."),
443 .islist = 1,
444 .get = linuxdvb_satconf_class_network_get3,
445 .set = linuxdvb_satconf_class_network_set3,
446 .list = linuxdvb_satconf_class_network_enum,
447 .rend = linuxdvb_satconf_class_network_rend3,
448 .opts = PO_NOSAVE,
449 },
450 {}
451 }
452 };
453
454 /*
455 * Unicable (EN50494)
456 */
457 static const void *
linuxdvb_satconf_class_en50494_id_get(void * p)458 linuxdvb_satconf_class_en50494_id_get ( void *p )
459 {
460 linuxdvb_satconf_t *ls = p;
461 linuxdvb_satconf_ele_t *lse = TAILQ_FIRST(&ls->ls_elements);
462 return &(((linuxdvb_en50494_t*)lse->lse_en50494)->le_id);
463 }
464
465 static int
linuxdvb_satconf_class_en50494_id_set(void * p,const void * v)466 linuxdvb_satconf_class_en50494_id_set
467 ( void *p, const void *v )
468 {
469 linuxdvb_satconf_t *ls = p;
470 linuxdvb_satconf_ele_t *lse;
471 TAILQ_FOREACH(lse, &ls->ls_elements, lse_link)
472 (((linuxdvb_en50494_t*)lse->lse_en50494)->le_id) = *(uint16_t*)v;
473 return 1;
474 }
475
476 static const void *
linuxdvb_satconf_class_en50494_pin_get(void * p)477 linuxdvb_satconf_class_en50494_pin_get ( void *p )
478 {
479 linuxdvb_satconf_t *ls = p;
480 linuxdvb_satconf_ele_t *lse = TAILQ_FIRST(&ls->ls_elements);
481 return &(((linuxdvb_en50494_t*)lse->lse_en50494)->le_pin);
482 }
483
484 static int
linuxdvb_satconf_class_en50494_pin_set(void * p,const void * v)485 linuxdvb_satconf_class_en50494_pin_set
486 ( void *p, const void *v )
487 {
488 linuxdvb_satconf_t *ls = p;
489 linuxdvb_satconf_ele_t *lse;
490 TAILQ_FOREACH(lse, &ls->ls_elements, lse_link)
491 (((linuxdvb_en50494_t*)lse->lse_en50494)->le_pin) = *(uint16_t*)v;
492 return 1;
493 }
494
495 static const void *
linuxdvb_satconf_class_en50494_freq_get(void * p)496 linuxdvb_satconf_class_en50494_freq_get ( void *p )
497 {
498 linuxdvb_satconf_t *ls = p;
499 linuxdvb_satconf_ele_t *lse = TAILQ_FIRST(&ls->ls_elements);
500 return &(((linuxdvb_en50494_t*)lse->lse_en50494)->le_frequency);
501 }
502
503 static int
linuxdvb_satconf_class_en50494_freq_set(void * p,const void * v)504 linuxdvb_satconf_class_en50494_freq_set
505 ( void *p, const void *v )
506 {
507 linuxdvb_satconf_t *ls = p;
508 linuxdvb_satconf_ele_t *lse;
509 TAILQ_FOREACH(lse, &ls->ls_elements, lse_link)
510 (((linuxdvb_en50494_t*)lse->lse_en50494)->le_frequency) = *(uint16_t*)v;
511 return 1;
512 }
513
514 const idclass_t linuxdvb_satconf_en50494_class =
515 {
516 .ic_super = &linuxdvb_satconf_class,
517 .ic_class = "linuxdvb_satconf_en50494",
518 .ic_doc = tvh_doc_linuxdvb_satconf_class,
519 .ic_caption = N_("TV Adapters - SatConfig - EN50494/UniCable I"),
520 .ic_properties = (const property_t[]) {
521 {
522 .type = PT_U16,
523 .id = "id",
524 .name = N_("SCR (ID)"),
525 .desc = N_("SCR (Satellite Channel Router) ID."),
526 .get = linuxdvb_satconf_class_en50494_id_get,
527 .set = linuxdvb_satconf_class_en50494_id_set,
528 .list = linuxdvb_en50494_id_list,
529 .opts = PO_NOSAVE,
530 },
531 {
532 .type = PT_U16,
533 .id = "pin",
534 .name = N_("PIN"),
535 .desc = N_("PIN."),
536 .get = linuxdvb_satconf_class_en50494_pin_get,
537 .set = linuxdvb_satconf_class_en50494_pin_set,
538 .list = linuxdvb_en50494_pin_list,
539 .opts = PO_NOSAVE,
540 },
541 {
542 .type = PT_U16,
543 .id = "frequency",
544 .name = N_("Frequency (MHz)"),
545 .desc = N_("Frequency (in MHz)."),
546 .get = linuxdvb_satconf_class_en50494_freq_get,
547 .set = linuxdvb_satconf_class_en50494_freq_set,
548 .opts = PO_NOSAVE,
549 },
550 {
551 .type = PT_STR,
552 .id = "network_a",
553 .name = N_("Network A"),
554 .desc = N_("Network for port A."),
555 .islist = 1,
556 .get = linuxdvb_satconf_class_network_get0,
557 .set = linuxdvb_satconf_class_network_set0,
558 .list = linuxdvb_satconf_class_network_enum,
559 .rend = linuxdvb_satconf_class_network_rend0,
560 .opts = PO_NOSAVE,
561 },
562 {
563 .type = PT_STR,
564 .id = "network_b",
565 .name = N_("Network B"),
566 .desc = N_("Network for port B."),
567 .islist = 1,
568 .get = linuxdvb_satconf_class_network_get1,
569 .set = linuxdvb_satconf_class_network_set1,
570 .list = linuxdvb_satconf_class_network_enum,
571 .rend = linuxdvb_satconf_class_network_rend1,
572 .opts = PO_NOSAVE,
573 },
574 {}
575 }
576 };
577
578 const idclass_t linuxdvb_satconf_en50607_class =
579 {
580 .ic_super = &linuxdvb_satconf_class,
581 .ic_class = "linuxdvb_satconf_en50607",
582 .ic_doc = tvh_doc_linuxdvb_satconf_class,
583 .ic_caption = N_("TV Adapters - SatConfig - EN50607/UniCable II"),
584 .ic_properties = (const property_t[]) {
585 {
586 .type = PT_U16,
587 .id = "id",
588 .name = N_("SCR (ID)"),
589 .desc = N_("SCR (Satellite Channel Router) ID."),
590 .get = linuxdvb_satconf_class_en50494_id_get,
591 .set = linuxdvb_satconf_class_en50494_id_set,
592 .list = linuxdvb_en50607_id_list,
593 .opts = PO_NOSAVE,
594 },
595 {
596 .type = PT_U16,
597 .id = "pin",
598 .name = N_("PIN"),
599 .desc = N_("PIN."),
600 .get = linuxdvb_satconf_class_en50494_pin_get,
601 .set = linuxdvb_satconf_class_en50494_pin_set,
602 .list = linuxdvb_en50494_pin_list,
603 .opts = PO_NOSAVE,
604 },
605 {
606 .type = PT_U16,
607 .id = "frequency",
608 .name = N_("Frequency (MHz)"),
609 .desc = N_("Frequency (in MHz)."),
610 .get = linuxdvb_satconf_class_en50494_freq_get,
611 .set = linuxdvb_satconf_class_en50494_freq_set,
612 .opts = PO_NOSAVE,
613 },
614 {
615 .type = PT_STR,
616 .id = "network_a",
617 .name = N_("Network A"),
618 .desc = N_("Network for port A."),
619 .islist = 1,
620 .get = linuxdvb_satconf_class_network_get0,
621 .set = linuxdvb_satconf_class_network_set0,
622 .list = linuxdvb_satconf_class_network_enum,
623 .rend = linuxdvb_satconf_class_network_rend0,
624 .opts = PO_NOSAVE,
625 },
626 {
627 .type = PT_STR,
628 .id = "network_b",
629 .name = N_("Network B"),
630 .desc = N_("Network for port B."),
631 .islist = 1,
632 .get = linuxdvb_satconf_class_network_get1,
633 .set = linuxdvb_satconf_class_network_set1,
634 .list = linuxdvb_satconf_class_network_enum,
635 .rend = linuxdvb_satconf_class_network_rend1,
636 .opts = PO_NOSAVE,
637 },
638 {
639 .type = PT_STR,
640 .id = "network_c",
641 .name = N_("Network C"),
642 .desc = N_("Network for port C."),
643 .islist = 1,
644 .get = linuxdvb_satconf_class_network_get2,
645 .set = linuxdvb_satconf_class_network_set2,
646 .list = linuxdvb_satconf_class_network_enum,
647 .rend = linuxdvb_satconf_class_network_rend2,
648 .opts = PO_NOSAVE,
649 },
650 {
651 .type = PT_STR,
652 .id = "network_d",
653 .name = N_("Network D"),
654 .desc = N_("Network for port D."),
655 .islist = 1,
656 .get = linuxdvb_satconf_class_network_get3,
657 .set = linuxdvb_satconf_class_network_set3,
658 .list = linuxdvb_satconf_class_network_enum,
659 .rend = linuxdvb_satconf_class_network_rend3,
660 .opts = PO_NOSAVE,
661 },
662 {}
663 }
664 };
665
666 /*
667 * Advanced
668 */
669 const idclass_t linuxdvb_satconf_advanced_class =
670 {
671 .ic_super = &linuxdvb_satconf_class,
672 .ic_class = "linuxdvb_satconf_advanced",
673 .ic_doc = tvh_doc_linuxdvb_satconf_class,
674 .ic_caption = N_("TV Adapters - SatConfig - Advanced"),
675 .ic_get_childs = linuxdvb_satconf_class_get_childs,
676 .ic_properties = (const property_t[]) {
677 {
678 .type = PT_INT,
679 .id = "orbital_pos",
680 .name = N_("Orbital positions"),
681 .desc = N_("Orbital positions."),
682 .get = linuxdvb_satconf_class_orbitalpos_get,
683 .set = linuxdvb_satconf_class_orbitalpos_set,
684 },
685 {
686 .type = PT_BOOL,
687 .id = "switch_rotor",
688 .name = N_("Switch before rotor"),
689 .desc = N_("If the DiseqC switch is located before the rotor "
690 "(i.e. tuner - switch - rotor), enable this."),
691 .off = offsetof(linuxdvb_satconf_t, ls_switch_rotor),
692 .opts = PO_ADVANCED,
693 },
694 {
695 .type = PT_U32,
696 .id = "max_rotor_move",
697 .name = N_("Rotor initialization time (seconds)"),
698 .desc = N_("Upon start, Tvheadend doesn't know the last rotor "
699 "position. This value defines the initial rotor "
700 "movement. TVHeadend waits the specified time when "
701 "the first movement is requested."),
702 .off = offsetof(linuxdvb_satconf_t, ls_max_rotor_move),
703 .opts = PO_ADVANCED,
704 .def.u32 = 120
705 },
706 {
707 .type = PT_U32,
708 .id = "min_rotor_move",
709 .name = N_("Minimum rotor time (seconds)"),
710 .desc = N_("The minimum delay after the rotor movement "
711 "command is sent."),
712 .off = offsetof(linuxdvb_satconf_t, ls_min_rotor_move),
713 .opts = PO_ADVANCED,
714 },
715 {
716 .type = PT_DBL,
717 .id = "site_lat",
718 .name = N_("Site latitude"),
719 .desc = N_("Site latitude."),
720 .off = offsetof(linuxdvb_satconf_t, ls_site_lat),
721 .opts = PO_ADVANCED,
722 },
723 {
724 .type = PT_DBL,
725 .id = "site_lon",
726 .name = N_("Site longitude"),
727 .desc = N_("Site longitude."),
728 .off = offsetof(linuxdvb_satconf_t, ls_site_lon),
729 .opts = PO_ADVANCED,
730 },
731 {
732 .type = PT_BOOL,
733 .id = "site_lat_south",
734 .name = N_("Southern hemisphere (latitude direction)"),
735 .desc = N_("Southern hemisphere (latitude direction)."),
736 .off = offsetof(linuxdvb_satconf_t, ls_site_lat_south),
737 .opts = PO_ADVANCED,
738 .def.i = 0
739 },
740 {
741 .type = PT_BOOL,
742 .id = "site_lon_west",
743 .name = N_("Western hemisphere (latitude direction)"),
744 .desc = N_("Western hemisphere (latitude direction)."),
745 .off = offsetof(linuxdvb_satconf_t, ls_site_lon_west),
746 .opts = PO_ADVANCED,
747 .def.i = 0
748 },
749 {
750 .type = PT_INT,
751 .id = "site_altitude",
752 .name = N_("Altitude (meters)"),
753 .desc = N_("Altitude (in meters)."),
754 .off = offsetof(linuxdvb_satconf_t, ls_site_altitude),
755 .opts = PO_ADVANCED,
756 .def.i = 0
757 },
758 {
759 .type = PT_U32,
760 .id = "motor_rate",
761 .name = N_("Motor rate (milliseconds/deg)"),
762 .desc = N_("Motor rate (in milliseconds/deg)."),
763 .off = offsetof(linuxdvb_satconf_t, ls_motor_rate),
764 },
765 {}
766 }
767 };
768
769
770 /* **************************************************************************
771 * Types
772 * *************************************************************************/
773
774 /* Types/classes */
775 static struct linuxdvb_satconf_type linuxdvb_satconf_types[] = {
776 {
777 .type = "simple",
778 .name = N_("Universal LNB only"),
779 .idc = &linuxdvb_satconf_lnbonly_class,
780 .ports = 1,
781 .enable = 1,
782 },
783 {
784 .type = "2port",
785 .name = N_("2-Port switch (universal LNB)"),
786 .idc = &linuxdvb_satconf_2port_class,
787 .ports = 2,
788 .enable = 1,
789 },
790 {
791 .type = "4port",
792 .name = N_("4-Port switch (universal LNB)"),
793 .idc = &linuxdvb_satconf_4port_class,
794 .ports = 4,
795 .enable = 1,
796 },
797 {
798 .type = "en50494",
799 .name = N_("Unicable I switch (universal LNB)"),
800 .idc = &linuxdvb_satconf_en50494_class,
801 .ports = 2,
802 .enable = 1,
803 },
804 {
805 .type = "en50607",
806 .name = N_("Unicable II switch (universal LNB)"),
807 .idc = &linuxdvb_satconf_en50607_class,
808 .ports = 4,
809 .enable = 1,
810 },
811 {
812 .type = "advanced",
813 .name = N_("Advanced (non-universal LNBs, rotors, etc.)"),
814 .idc = &linuxdvb_satconf_advanced_class,
815 .ports = 0,
816 .enable = 0,
817 },
818 };
819
820 /* Find type (with default) */
821 static struct linuxdvb_satconf_type *
linuxdvb_satconf_type_find(const char * type)822 linuxdvb_satconf_type_find ( const char *type )
823 {
824 int i;
825 for (i = 0; i < ARRAY_SIZE(linuxdvb_satconf_types); i++)
826 if (!strcmp(type ?: "", linuxdvb_satconf_types[i].type))
827 return linuxdvb_satconf_types+i;
828 return linuxdvb_satconf_types;
829 }
830
831 /* List of types */
832 htsmsg_t *
linuxdvb_satconf_type_list(void * p,const char * lang)833 linuxdvb_satconf_type_list ( void *p, const char *lang )
834 {
835 int i;
836 htsmsg_t *e, *m = htsmsg_create_list();
837 for (i = 0; i < ARRAY_SIZE(linuxdvb_satconf_types); i++) {
838 e = htsmsg_create_map();
839 htsmsg_add_str(e, "key", linuxdvb_satconf_types[i].type);
840 htsmsg_add_str(e, "val", linuxdvb_satconf_types[i].name);
841 htsmsg_add_msg(m, NULL, e);
842 }
843 return m;
844 }
845
846 /*
847 * Frontend callbacks
848 */
849
850 static linuxdvb_satconf_ele_t *
linuxdvb_satconf_find_ele(linuxdvb_satconf_t * ls,mpegts_mux_t * mux)851 linuxdvb_satconf_find_ele( linuxdvb_satconf_t *ls, mpegts_mux_t *mux )
852 {
853 linuxdvb_satconf_ele_t *lse;
854 TAILQ_FOREACH(lse, &ls->ls_elements, lse_link) {
855 if (idnode_set_exists(lse->lse_networks, &mux->mm_network->mn_id))
856 return lse;
857 }
858 return NULL;
859 }
860
861 int
linuxdvb_satconf_get_priority(linuxdvb_satconf_t * ls,mpegts_mux_t * mm)862 linuxdvb_satconf_get_priority
863 ( linuxdvb_satconf_t *ls, mpegts_mux_t *mm )
864 {
865 linuxdvb_satconf_ele_t *lse = linuxdvb_satconf_find_ele(ls, mm);
866 return lse ? lse->lse_priority : 0;
867 }
868
869 void
linuxdvb_satconf_post_stop_mux(linuxdvb_satconf_t * ls)870 linuxdvb_satconf_post_stop_mux
871 ( linuxdvb_satconf_t *ls )
872 {
873 ls->ls_mmi = NULL;
874 mtimer_disarm(&ls->ls_diseqc_timer);
875 if (ls->ls_frontend && ls->ls_lnb_poweroff) {
876 linuxdvb_diseqc_set_volt(ls, -1);
877 linuxdvb_satconf_reset(ls);
878 }
879 }
880
881 int
linuxdvb_satconf_get_grace(linuxdvb_satconf_t * ls,mpegts_mux_t * mm)882 linuxdvb_satconf_get_grace
883 ( linuxdvb_satconf_t *ls, mpegts_mux_t *mm )
884 {
885 linuxdvb_satconf_ele_t *lse = linuxdvb_satconf_find_ele(ls, mm);
886 if (lse == NULL)
887 return 0;
888
889 int i, r = 10;
890 linuxdvb_diseqc_t *lds[] = {
891 (linuxdvb_diseqc_t*)lse->lse_en50494,
892 (linuxdvb_diseqc_t*)lse->lse_switch,
893 (linuxdvb_diseqc_t*)lse->lse_rotor,
894 (linuxdvb_diseqc_t*)lse->lse_lnb
895 };
896
897 /* Add diseqc delay */
898 for (i = 0; i < 3; i++) {
899 if (lds[i] && lds[i]->ld_grace)
900 r += lds[i]->ld_grace(lds[i], (dvb_mux_t*)mm);
901 }
902
903 return r;
904 }
905
906 int
linuxdvb_satconf_start(linuxdvb_satconf_t * ls,int delay,int vol)907 linuxdvb_satconf_start ( linuxdvb_satconf_t *ls, int delay, int vol )
908 {
909 if (vol >= 0 && linuxdvb_diseqc_set_volt(ls, vol))
910 return -1;
911
912 if (ls->ls_last_tone_off != 1) {
913 tvhtrace(LS_DISEQC, "initial tone off");
914 if (ioctl(linuxdvb_satconf_fe_fd(ls), FE_SET_TONE, SEC_TONE_OFF)) {
915 tvherror(LS_DISEQC, "failed to disable tone");
916 return -1;
917 }
918 ls->ls_last_tone_off = 1;
919 }
920 /* the linuxdvb_diseqc_set_volt() fcn already sleeps for 15ms */
921 if (delay > 15) {
922 tvhtrace(LS_DISEQC, "initial sleep %dms", delay);
923 tvh_safe_usleep((delay-15)*1000);
924 }
925 return 0;
926 }
927
928 static void linuxdvb_satconf_ele_tune_cb ( void *o );
929
930 static int
linuxdvb_satconf_ele_tune(linuxdvb_satconf_ele_t * lse)931 linuxdvb_satconf_ele_tune ( linuxdvb_satconf_ele_t *lse )
932 {
933 int r, i, vol, pol, band, freq;
934 uint32_t f;
935 linuxdvb_satconf_t *ls = lse->lse_parent;
936
937 /* Get beans in a row */
938 mpegts_mux_instance_t *mmi = ls->ls_mmi;
939 linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)ls->ls_frontend;
940 dvb_mux_t *lm = (dvb_mux_t*)mmi->mmi_mux;
941 linuxdvb_diseqc_t *lds[] = {
942 ls->ls_switch_rotor ? (linuxdvb_diseqc_t*)lse->lse_switch :
943 (linuxdvb_diseqc_t*)lse->lse_rotor,
944 ls->ls_switch_rotor ? (linuxdvb_diseqc_t*)lse->lse_rotor :
945 (linuxdvb_diseqc_t*)lse->lse_switch,
946 (linuxdvb_diseqc_t*)lse->lse_en50494,
947 (linuxdvb_diseqc_t*)lse->lse_lnb
948 };
949
950 if (lse->lse_lnb) {
951 pol = lse->lse_lnb->lnb_pol (lse->lse_lnb, lm) & 0x1;
952 band = lse->lse_lnb->lnb_band(lse->lse_lnb, lm) & 0x1;
953 freq = lse->lse_lnb->lnb_freq(lse->lse_lnb, lm);
954 } else {
955 tvherror(LS_LINUXDVB, "LNB is not defined!!!");
956 return -1;
957 }
958 if (!lse->lse_en50494) {
959 vol = pol;
960 } else {
961 vol = 0; /* 13V */
962 }
963
964 /*
965 * Disable tone (en50494 don't use tone)
966 * The 22khz tone is used for signalling band (universal LNB)
967 * and also for the DiseqC commands. It's necessary to turn
968 * tone off before communication with DiseqC devices.
969 */
970
971 if (!lse->lse_en50494 || lse->lse_switch || lse->lse_rotor) {
972 if (ls->ls_diseqc_full) {
973 ls->ls_last_tone_off = 0; /* force */
974 if (linuxdvb_satconf_start(ls, 0, vol))
975 return -1;
976 }
977 }
978
979 /* Diseqc */
980 for (i = ls->ls_diseqc_idx; i < ARRAY_SIZE(lds); i++) {
981 if (!lds[i]) continue;
982 r = lds[i]->ld_tune(lds[i], lm, ls, lse, vol, pol, band, freq);
983
984 /* Error */
985 if (r < 0) return r;
986
987 /* Pending */
988 if (r != 0) {
989 tvhtrace(LS_DISEQC, "waiting %d seconds to finish setup for %s", r, lds[i]->ld_type);
990 mtimer_arm_rel(&ls->ls_diseqc_timer, linuxdvb_satconf_ele_tune_cb, lse, sec2mono(r));
991 ls->ls_diseqc_idx = i + 1;
992 return 0;
993 }
994 }
995
996 /* Do post things (store position for rotor) */
997 if (lse->lse_rotor)
998 lse->lse_rotor->ld_post(lse->lse_rotor, lm, ls, lse);
999
1000 /* LNB settings */
1001 /* EN50494 devices have another mechanism to select polarization */
1002
1003 /* Set the voltage */
1004 if (linuxdvb_diseqc_set_volt(ls, vol))
1005 return -1;
1006
1007 /* Set the tone (en50494 don't use tone) */
1008 if (!lse->lse_en50494) {
1009 if (ls->ls_last_tone_off != band + 1) {
1010 ls->ls_last_tone_off = 0;
1011 tvhtrace(LS_DISEQC, "set diseqc tone %s", band ? "on" : "off");
1012 if (ioctl(lfe->lfe_fe_fd, FE_SET_TONE, band ? SEC_TONE_ON : SEC_TONE_OFF)) {
1013 tvherror(LS_DISEQC, "failed to set diseqc tone (e=%s)", strerror(errno));
1014 return -1;
1015 }
1016 ls->ls_last_tone_off = band + 1;
1017 tvh_safe_usleep(20000); // Allow LNB to settle before tuning
1018 }
1019 }
1020
1021 /* Frontend */
1022 /* use en50494 tuning frequency, if needed (not channel frequency) */
1023 f = lse->lse_en50494
1024 ? ((linuxdvb_en50494_t*)lse->lse_en50494)->le_tune_freq
1025 : freq;
1026 return linuxdvb_frontend_tune1(lfe, mmi, f);
1027 }
1028
1029 static void
linuxdvb_satconf_ele_tune_cb(void * o)1030 linuxdvb_satconf_ele_tune_cb ( void *o )
1031 {
1032 (void)linuxdvb_satconf_ele_tune(o);
1033 // TODO: how to signal error
1034 }
1035
1036 int
linuxdvb_satconf_lnb_freq(linuxdvb_satconf_t * ls,mpegts_mux_instance_t * mmi)1037 linuxdvb_satconf_lnb_freq
1038 ( linuxdvb_satconf_t *ls, mpegts_mux_instance_t *mmi )
1039 {
1040 int f;
1041 linuxdvb_satconf_ele_t *lse = linuxdvb_satconf_find_ele(ls, mmi->mmi_mux);
1042 dvb_mux_t *lm = (dvb_mux_t*)mmi->mmi_mux;
1043
1044 if (!lse->lse_lnb)
1045 return -1;
1046
1047 f = lse->lse_lnb->lnb_freq(lse->lse_lnb, lm);
1048 if (f == (uint32_t)-1)
1049 return -1;
1050
1051 /* calculate tuning frequency for en50494 */
1052 if (lse->lse_en50494) {
1053 f = lse->lse_en50494->ld_freq(lse->lse_en50494, lm, f);
1054 if (f < 0) {
1055 tvherror(LS_EN50494, "invalid tuning freq");
1056 return -1;
1057 }
1058 }
1059 return f;
1060 }
1061
1062 int
linuxdvb_satconf_start_mux(linuxdvb_satconf_t * ls,mpegts_mux_instance_t * mmi,int skip_diseqc)1063 linuxdvb_satconf_start_mux
1064 ( linuxdvb_satconf_t *ls, mpegts_mux_instance_t *mmi, int skip_diseqc )
1065 {
1066 int r, f;
1067 linuxdvb_satconf_ele_t *lse = linuxdvb_satconf_find_ele(ls, mmi->mmi_mux);
1068 linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)ls->ls_frontend;
1069
1070 /* Not fully configured */
1071 if (!lse) return SM_CODE_TUNING_FAILED;
1072
1073 /* Test run */
1074 // Note: basically this ensures the tuning params are acceptable
1075 // for the FE, so that if they're not we don't have to wait
1076 // for things like rotors and switches
1077 // the en50494 have to skip this test
1078 if (!lse->lse_lnb)
1079 return SM_CODE_TUNING_FAILED;
1080
1081 if (skip_diseqc) {
1082 f = linuxdvb_satconf_lnb_freq(ls, mmi);
1083 if (f < 0)
1084 return SM_CODE_TUNING_FAILED;
1085 return linuxdvb_frontend_tune1(lfe, mmi, f);
1086 }
1087 if (ls->ls_early_tune) {
1088 f = linuxdvb_satconf_lnb_freq(ls, mmi);
1089 if (f < 0)
1090 return SM_CODE_TUNING_FAILED;
1091 r = linuxdvb_frontend_tune0(lfe, mmi, f);
1092 if (r) return r;
1093 } else {
1094 /* Clear the frontend settings, open frontend fd */
1095 r = linuxdvb_frontend_clear(lfe, mmi);
1096 if (r) return r;
1097 }
1098
1099 /* Diseqc */
1100 ls->ls_mmi = mmi;
1101 ls->ls_diseqc_idx = 0;
1102 return linuxdvb_satconf_ele_tune(lse);
1103 }
1104
1105 /*
1106 *
1107 */
1108 void
linuxdvb_satconf_reset(linuxdvb_satconf_t * ls)1109 linuxdvb_satconf_reset
1110 ( linuxdvb_satconf_t *ls )
1111 {
1112 ls->ls_last_switch = NULL;
1113 ls->ls_last_vol = 0;
1114 ls->ls_last_toneburst = 0;
1115 ls->ls_last_tone_off = 0;
1116 }
1117
1118 /*
1119 * return 0 if passed mux cannot be used simultanously with given
1120 * diseqc config
1121 */
1122 int
linuxdvb_satconf_match_mux(linuxdvb_satconf_t * ls,mpegts_mux_t * mm)1123 linuxdvb_satconf_match_mux
1124 ( linuxdvb_satconf_t *ls, mpegts_mux_t *mm )
1125 {
1126 mpegts_mux_instance_t *mmi = ls->ls_mmi;
1127
1128 if (mmi == NULL || mmi->mmi_mux == NULL)
1129 return 1;
1130
1131 linuxdvb_satconf_ele_t *lse1 = linuxdvb_satconf_find_ele(ls, mm);
1132 linuxdvb_satconf_ele_t *lse2 = linuxdvb_satconf_find_ele(ls, mmi->mmi_mux);
1133 dvb_mux_t *lm1 = (dvb_mux_t*)mmi->mmi_mux;
1134 dvb_mux_t *lm2 = (dvb_mux_t*)mm;
1135
1136 #if ENABLE_TRACE
1137 char buf1[256], buf2[256];
1138 dvb_mux_conf_str(&lm1->lm_tuning, buf1, sizeof(buf1));
1139 dvb_mux_conf_str(&lm2->lm_tuning, buf2, sizeof(buf2));
1140 tvhtrace(LS_DISEQC, "match mux 1 - %s", buf1);
1141 tvhtrace(LS_DISEQC, "match mux 2 - %s", buf2);
1142 #endif
1143
1144 if (lse1 != lse2) {
1145 tvhtrace(LS_DISEQC, "match position failed");
1146 return 0;
1147 }
1148 if (!lse1->lse_lnb->lnb_match(lse1->lse_lnb, lm1, lm2)) {
1149 tvhtrace(LS_DISEQC, "match LNB failed");
1150 return 0;
1151 }
1152 if (lse1->lse_en50494 && !lse1->lse_en50494->ld_match(lse1->lse_en50494, lm1, lm2)) {
1153 tvhtrace(LS_DISEQC, "match en50494 failed");
1154 return 0;
1155 }
1156 return 1;
1157 }
1158
1159 /* **************************************************************************
1160 * Create/Delete satconf
1161 * *************************************************************************/
1162
1163 linuxdvb_satconf_t *
linuxdvb_satconf_create(linuxdvb_frontend_t * lfe,htsmsg_t * conf)1164 linuxdvb_satconf_create
1165 ( linuxdvb_frontend_t *lfe, htsmsg_t *conf )
1166 {
1167 int i;
1168 htsmsg_t *l, *e;
1169 htsmsg_field_t *f;
1170 linuxdvb_satconf_ele_t *lse;
1171 const char *str, *type = NULL, *uuid = NULL;
1172 struct linuxdvb_satconf_type *lst;
1173
1174 if (conf) {
1175 type = htsmsg_get_str(conf, "type");
1176 uuid = htsmsg_get_str(conf, "uuid");
1177 }
1178
1179 lst = linuxdvb_satconf_type_find(type);
1180 assert(lst);
1181
1182 linuxdvb_satconf_t *ls = calloc(1, sizeof(linuxdvb_satconf_t));
1183 ls->ls_frontend = (mpegts_input_t*)lfe;
1184 ls->ls_type = lst->type;
1185 TAILQ_INIT(&ls->ls_elements);
1186
1187 ls->ls_early_tune = 1;
1188 ls->ls_diseqc_full = 1;
1189 ls->ls_max_rotor_move = 120;
1190
1191 /* Create node */
1192 if (idnode_insert(&ls->ls_id, uuid, lst->idc, 0)) {
1193 free(ls);
1194 return NULL;
1195 }
1196
1197 /* Load config */
1198 if (conf) {
1199
1200 /* Load elements */
1201 // Note: we do things this way else the orbital_pos field in advanced
1202 // will result in extra elements
1203 if ((l = htsmsg_get_list(conf, "elements"))) {
1204 HTSMSG_FOREACH(f, l) {
1205 if (!(e = htsmsg_field_get_map(f))) continue;
1206
1207 /* Fix config */
1208 if ((str = htsmsg_get_str(e, "network")) &&
1209 !htsmsg_get_list(e, "networks")) {
1210 htsmsg_t *l = htsmsg_create_list();
1211 htsmsg_add_str(l, NULL, str);
1212 htsmsg_add_msg(e, "networks", l);
1213 }
1214 if (lst->enable)
1215 htsmsg_set_bool(e, "enabled", 1);
1216 lse = linuxdvb_satconf_ele_create0(htsmsg_get_str(e, "uuid"), e, ls);
1217 }
1218 }
1219
1220 /* Load node */
1221 idnode_load(&ls->ls_id, conf);
1222 }
1223
1224 /* Create elements */
1225 lse = TAILQ_FIRST(&ls->ls_elements);
1226 for (i = 0; i < lst->ports; i++) {
1227 if (!lse)
1228 lse = linuxdvb_satconf_ele_create0(NULL, NULL, ls);
1229 if (lst->enable)
1230 lse->lse_enabled = 1;
1231 if (!lse->lse_lnb)
1232 lse->lse_lnb = linuxdvb_lnb_create0(NULL, NULL, lse);
1233 if (lst->ports > 1) {
1234 if (!strcmp(lst->type, "en50494")) {
1235 if (!lse->lse_en50494)
1236 lse->lse_en50494 = linuxdvb_en50494_create0(UNICABLE_I_NAME, NULL, lse, i);
1237 } else if (!strcmp(lst->type, "en50607")) {
1238 if (!lse->lse_en50494)
1239 lse->lse_en50494 = linuxdvb_en50494_create0(UNICABLE_II_NAME, NULL, lse, i);
1240 } else {
1241 if (!lse->lse_switch)
1242 lse->lse_switch = linuxdvb_switch_create0("Generic", NULL, lse, i, -1);
1243 }
1244 }
1245 lse = TAILQ_NEXT(lse, lse_link);
1246 }
1247
1248 return ls;
1249 }
1250
1251 void
linuxdvb_satconf_save(linuxdvb_satconf_t * ls,htsmsg_t * m)1252 linuxdvb_satconf_save ( linuxdvb_satconf_t *ls, htsmsg_t *m )
1253 {
1254 linuxdvb_satconf_ele_t *lse;
1255 htsmsg_t *l, *e, *c;
1256 char ubuf[UUID_HEX_SIZE];
1257 htsmsg_add_str(m, "type", ls->ls_type);
1258 idnode_save(&ls->ls_id, m);
1259 l = htsmsg_create_list();
1260 TAILQ_FOREACH(lse, &ls->ls_elements, lse_link){
1261 e = htsmsg_create_map();
1262 idnode_save(&lse->lse_id, e);
1263 htsmsg_add_str(e, "uuid", idnode_uuid_as_str(&lse->lse_id, ubuf));
1264 if (lse->lse_lnb) {
1265 c = htsmsg_create_map();
1266 idnode_save(&lse->lse_lnb->ld_id, c);
1267 htsmsg_add_msg(e, "lnb_conf", c);
1268 }
1269 if (lse->lse_switch) {
1270 c = htsmsg_create_map();
1271 idnode_save(&lse->lse_switch->ld_id, c);
1272 htsmsg_add_msg(e, "switch_conf", c);
1273 }
1274 if (lse->lse_rotor) {
1275 c = htsmsg_create_map();
1276 idnode_save(&lse->lse_rotor->ld_id, c);
1277 htsmsg_add_msg(e, "rotor_conf", c);
1278 }
1279 if (lse->lse_en50494) {
1280 c = htsmsg_create_map();
1281 idnode_save(&lse->lse_en50494->ld_id, c);
1282 htsmsg_add_msg(e, "en50494_conf", c);
1283 }
1284 htsmsg_add_msg(l, NULL, e);
1285 }
1286 htsmsg_add_msg(m, "elements", l);
1287 }
1288
1289 /* **************************************************************************
1290 * Class definition
1291 * *************************************************************************/
1292
1293 extern const idclass_t mpegts_input_class;
1294
1295 static const void *
linuxdvb_satconf_ele_class_network_get(void * o)1296 linuxdvb_satconf_ele_class_network_get( void *o )
1297 {
1298 linuxdvb_satconf_ele_t *ls = o;
1299 return idnode_set_as_htsmsg(ls->lse_networks);
1300 }
1301
1302 static int
linuxdvb_satconf_ele_class_network_set(void * o,const void * p)1303 linuxdvb_satconf_ele_class_network_set( void *o, const void *p )
1304 {
1305 linuxdvb_satconf_ele_t *ls = o;
1306 const htsmsg_t *msg = p;
1307 mpegts_network_t *mn;
1308 idnode_set_t *n = idnode_set_create(0);
1309 htsmsg_field_t *f;
1310 const char *str;
1311 int i, save;
1312 char ubuf[UUID_HEX_SIZE];
1313
1314 HTSMSG_FOREACH(f, msg) {
1315 if (!(str = htsmsg_field_get_str(f))) continue;
1316 if (!(mn = mpegts_network_find(str))) continue;
1317 idnode_set_add(n, &mn->mn_id, NULL, NULL);
1318 }
1319
1320 save = n->is_count != ls->lse_networks->is_count;
1321 if (!save) {
1322 for (i = 0; i < n->is_count; i++)
1323 if (!idnode_set_exists(ls->lse_networks, n->is_array[i])) {
1324 save = 1;
1325 break;
1326 }
1327 }
1328 if (save) {
1329 /* update the local (antenna satconf) network list */
1330 idnode_set_free(ls->lse_networks);
1331 ls->lse_networks = n;
1332 /* update the input (frontend) network list */
1333 htsmsg_t *l = htsmsg_create_list();
1334 linuxdvb_satconf_t *sc = ls->lse_parent;
1335 linuxdvb_satconf_ele_t *lse;
1336 TAILQ_FOREACH(lse, &sc->ls_elements, lse_link) {
1337 for (i = 0; i < lse->lse_networks->is_count; i++) {
1338 if (!lse->lse_enabled) continue;
1339 htsmsg_add_str(l, NULL,
1340 idnode_uuid_as_str(lse->lse_networks->is_array[i], ubuf));
1341 }
1342 }
1343 mpegts_input_class_network_set(ls->lse_parent->ls_frontend, l);
1344 htsmsg_destroy(l);
1345 } else {
1346 idnode_set_free(n);
1347 }
1348 return save;
1349 }
1350
1351 static htsmsg_t *
linuxdvb_satconf_ele_class_network_enum(void * o,const char * lang)1352 linuxdvb_satconf_ele_class_network_enum( void *o, const char *lang )
1353 {
1354 linuxdvb_satconf_ele_t *ls = o;
1355 if (ls == NULL) return NULL;
1356 return mpegts_input_class_network_enum(ls->lse_parent->ls_frontend, lang);
1357 }
1358
1359 static char *
linuxdvb_satconf_ele_class_network_rend(void * o,const char * lang)1360 linuxdvb_satconf_ele_class_network_rend( void *o, const char *lang )
1361 {
1362 linuxdvb_satconf_ele_t *ls = o;
1363 htsmsg_t *l = idnode_set_as_htsmsg(ls->lse_networks);
1364 char *str = htsmsg_list_2_csv(l, ',', 1);
1365 htsmsg_destroy(l);
1366 return str;
1367 }
1368
1369 static int
linuxdvb_satconf_ele_class_lnbtype_set(void * o,const void * p)1370 linuxdvb_satconf_ele_class_lnbtype_set ( void *o, const void *p )
1371 {
1372 linuxdvb_satconf_ele_t *ls = o;
1373 const char *str = p;
1374 if (ls->lse_lnb && !strcmp(str ?: "", ls->lse_lnb->ld_type))
1375 return 0;
1376 if (ls->lse_lnb) linuxdvb_lnb_destroy(ls->lse_lnb);
1377 ls->lse_lnb = linuxdvb_lnb_create0(str, NULL, ls);
1378 return 1;
1379 }
1380
1381 static const void *
linuxdvb_satconf_ele_class_lnbtype_get(void * o)1382 linuxdvb_satconf_ele_class_lnbtype_get ( void *o )
1383 {
1384 linuxdvb_satconf_ele_t *ls = o;
1385 prop_ptr = ls->lse_lnb ? ls->lse_lnb->ld_type : NULL;
1386 return &prop_ptr;
1387 }
1388
1389 static int
linuxdvb_satconf_ele_class_en50494type_set(void * o,const void * p)1390 linuxdvb_satconf_ele_class_en50494type_set ( void *o, const void *p )
1391 {
1392 linuxdvb_satconf_ele_t *ls = o;
1393 const char *str = p;
1394 if (ls->lse_en50494)
1395 linuxdvb_en50494_destroy(ls->lse_en50494);
1396 ls->lse_en50494 = linuxdvb_en50494_create0(str, NULL, ls, 0);
1397 return 1;
1398 }
1399
1400 static const void *
linuxdvb_satconf_ele_class_en50494type_get(void * o)1401 linuxdvb_satconf_ele_class_en50494type_get ( void *o )
1402 {
1403 linuxdvb_satconf_ele_t *ls = o;
1404 prop_ptr = ls->lse_en50494 ? ls->lse_en50494->ld_type : NULL;
1405 return &prop_ptr;
1406 }
1407
1408 static int
linuxdvb_satconf_ele_class_switchtype_set(void * o,const void * p)1409 linuxdvb_satconf_ele_class_switchtype_set ( void *o, const void *p )
1410 {
1411 linuxdvb_satconf_ele_t *ls = o;
1412 const char *str = p;
1413 if (ls->lse_switch && !strcmp(str ?: "", ls->lse_switch->ld_type))
1414 return 0;
1415 if (ls->lse_switch) linuxdvb_switch_destroy(ls->lse_switch);
1416 ls->lse_switch = linuxdvb_switch_create0(str, NULL, ls, -1, -1);
1417 return 1;
1418 }
1419
1420 static const void *
linuxdvb_satconf_ele_class_switchtype_get(void * o)1421 linuxdvb_satconf_ele_class_switchtype_get ( void *o )
1422 {
1423 linuxdvb_satconf_ele_t *ls = o;
1424 prop_ptr = ls->lse_switch ? ls->lse_switch->ld_type : NULL;
1425 return &prop_ptr;
1426 }
1427
1428 static int
linuxdvb_satconf_ele_class_rotortype_set(void * o,const void * p)1429 linuxdvb_satconf_ele_class_rotortype_set ( void *o, const void *p )
1430 {
1431 linuxdvb_satconf_ele_t *ls = o;
1432 const char *str = p;
1433 if (ls->lse_rotor && !strcmp(str ?: "", ls->lse_rotor->ld_type))
1434 return 0;
1435 if (ls->lse_rotor) linuxdvb_rotor_destroy(ls->lse_rotor);
1436 ls->lse_rotor = linuxdvb_rotor_create0(str, NULL, ls);
1437 return 1;
1438 }
1439
1440 static const void *
linuxdvb_satconf_ele_class_rotortype_get(void * o)1441 linuxdvb_satconf_ele_class_rotortype_get ( void *o )
1442 {
1443 linuxdvb_satconf_ele_t *ls = o;
1444 prop_ptr = ls->lse_rotor ? ls->lse_rotor->ld_type : NULL;
1445 return &prop_ptr;
1446 }
1447
1448 static const char *
linuxdvb_satconf_ele_class_get_title(idnode_t * o,const char * lang)1449 linuxdvb_satconf_ele_class_get_title ( idnode_t *o, const char *lang )
1450 {
1451 return ((linuxdvb_satconf_ele_t *)o)->lse_name;
1452 }
1453
1454 static idnode_set_t *
linuxdvb_satconf_ele_class_get_childs(idnode_t * o)1455 linuxdvb_satconf_ele_class_get_childs ( idnode_t *o )
1456 {
1457 linuxdvb_satconf_ele_t *ls = (linuxdvb_satconf_ele_t*)o;
1458 idnode_set_t *is = idnode_set_create(0);
1459 if (ls->lse_lnb)
1460 idnode_set_add(is, &ls->lse_lnb->ld_id, NULL, NULL);
1461 if (ls->lse_switch)
1462 idnode_set_add(is, &ls->lse_switch->ld_id, NULL, NULL);
1463 if (ls->lse_rotor)
1464 idnode_set_add(is, &ls->lse_rotor->ld_id, NULL, NULL);
1465 if (ls->lse_en50494)
1466 idnode_set_add(is, &ls->lse_en50494->ld_id, NULL, NULL);
1467 return is;
1468 }
1469
1470 static void
linuxdvb_satconf_ele_class_changed(idnode_t * in)1471 linuxdvb_satconf_ele_class_changed ( idnode_t *in )
1472 {
1473 linuxdvb_satconf_ele_t *lse = (linuxdvb_satconf_ele_t*)in;
1474 linuxdvb_satconf_class_changed(&lse->lse_parent->ls_id);
1475 }
1476
1477 static const void *
linuxdvb_satconf_ele_class_active_get(void * obj)1478 linuxdvb_satconf_ele_class_active_get ( void *obj )
1479 {
1480 static int active;
1481 linuxdvb_satconf_ele_t *lse = obj;
1482 active = 0;
1483 if (*(int *)linuxdvb_frontend_class_active_get(lse->lse_parent->ls_frontend))
1484 active = lse->lse_enabled;
1485 return &active;
1486 }
1487
1488 const idclass_t linuxdvb_satconf_ele_class =
1489 {
1490 .ic_class = "linuxdvb_satconf_ele",
1491 .ic_caption = N_("Satconf"),
1492 .ic_doc = tvh_doc_linuxdvb_satconf_class,
1493 .ic_event = "linuxdvb_satconf_ele",
1494 .ic_get_title = linuxdvb_satconf_ele_class_get_title,
1495 .ic_get_childs = linuxdvb_satconf_ele_class_get_childs,
1496 .ic_changed = linuxdvb_satconf_ele_class_changed,
1497 .ic_properties = (const property_t[]) {
1498 {
1499 .type = PT_BOOL,
1500 .id = "active",
1501 .name = N_("Active"),
1502 .opts = PO_RDONLY | PO_NOSAVE | PO_NOUI,
1503 .get = linuxdvb_satconf_ele_class_active_get,
1504 },
1505 {
1506 .type = PT_BOOL,
1507 .id = "enabled",
1508 .name = N_("Enabled"),
1509 .off = offsetof(linuxdvb_satconf_ele_t, lse_enabled),
1510 },
1511 {
1512 .type = PT_STR,
1513 .id = "displayname",
1514 .name = N_("Name"),
1515 .off = offsetof(linuxdvb_satconf_ele_t, lse_name),
1516 .notify = idnode_notify_title_changed,
1517 },
1518 {
1519 .type = PT_INT,
1520 .id = "priority",
1521 .name = N_("Priority"),
1522 .off = offsetof(linuxdvb_satconf_ele_t, lse_priority),
1523 .def.i = 1,
1524 .opts = PO_ADVANCED,
1525 },
1526 {
1527 .type = PT_STR,
1528 .id = "networks",
1529 .name = N_("Networks"),
1530 .islist = 1,
1531 .set = linuxdvb_satconf_ele_class_network_set,
1532 .get = linuxdvb_satconf_ele_class_network_get,
1533 .list = linuxdvb_satconf_ele_class_network_enum,
1534 .rend = linuxdvb_satconf_ele_class_network_rend,
1535 },
1536 {
1537 .type = PT_STR,
1538 .id = "lnb_type",
1539 .name = N_("LNB type"),
1540 .set = linuxdvb_satconf_ele_class_lnbtype_set,
1541 .get = linuxdvb_satconf_ele_class_lnbtype_get,
1542 .list = linuxdvb_lnb_list,
1543 .def.s = "Universal",
1544 },
1545 {
1546 .type = PT_STR,
1547 .id = "switch_type",
1548 .name = N_("Switch type"),
1549 .set = linuxdvb_satconf_ele_class_switchtype_set,
1550 .get = linuxdvb_satconf_ele_class_switchtype_get,
1551 .list = linuxdvb_switch_list,
1552 .def.s = "None",
1553 },
1554 {
1555 .type = PT_STR,
1556 .id = "rotor_type",
1557 .name = N_("Rotor type"),
1558 .set = linuxdvb_satconf_ele_class_rotortype_set,
1559 .get = linuxdvb_satconf_ele_class_rotortype_get,
1560 .list = linuxdvb_rotor_list,
1561 .def.s = "None",
1562 },
1563 {
1564 .type = PT_STR,
1565 .id = "en50494_type",
1566 .name = N_("Unicable type"),
1567 .set = linuxdvb_satconf_ele_class_en50494type_set,
1568 .get = linuxdvb_satconf_ele_class_en50494type_get,
1569 .list = linuxdvb_en50494_list,
1570 .def.s = "None",
1571 },
1572 {}
1573 }
1574 };
1575
1576 /* **************************************************************************
1577 * Creation/Config
1578 * *************************************************************************/
1579
1580 void
linuxdvb_satconf_ele_destroy(linuxdvb_satconf_ele_t * ls)1581 linuxdvb_satconf_ele_destroy ( linuxdvb_satconf_ele_t *ls )
1582 {
1583 TAILQ_REMOVE(&ls->lse_parent->ls_elements, ls, lse_link);
1584 idnode_save_check(&ls->lse_id, 1);
1585 idnode_unlink(&ls->lse_id);
1586 if (ls->lse_lnb) linuxdvb_lnb_destroy(ls->lse_lnb);
1587 if (ls->lse_switch) linuxdvb_switch_destroy(ls->lse_switch);
1588 if (ls->lse_rotor) linuxdvb_rotor_destroy(ls->lse_rotor);
1589 if (ls->lse_en50494) linuxdvb_en50494_destroy(ls->lse_en50494);
1590 idnode_set_free(ls->lse_networks);
1591 free(ls->lse_name);
1592 free(ls);
1593 }
1594
1595 linuxdvb_satconf_ele_t *
linuxdvb_satconf_ele_create0(const char * uuid,htsmsg_t * conf,linuxdvb_satconf_t * ls)1596 linuxdvb_satconf_ele_create0
1597 ( const char *uuid, htsmsg_t *conf, linuxdvb_satconf_t *ls )
1598 {
1599 htsmsg_t *e;
1600 linuxdvb_satconf_ele_t *lse = calloc(1, sizeof(*lse));
1601 if (idnode_insert(&lse->lse_id, uuid, &linuxdvb_satconf_ele_class, 0)) {
1602 free(lse);
1603 return NULL;
1604 }
1605 lse->lse_networks = idnode_set_create(0);
1606 lse->lse_parent = ls;
1607 TAILQ_INSERT_TAIL(&ls->ls_elements, lse, lse_link);
1608 if (conf)
1609 idnode_load(&lse->lse_id, conf);
1610
1611 /* Config */
1612 if (conf) {
1613
1614 /* LNB */
1615 if (lse->lse_lnb && (e = htsmsg_get_map(conf, "lnb_conf")))
1616 idnode_load(&lse->lse_lnb->ld_id, e);
1617
1618 /* Switch */
1619 if (lse->lse_switch && (e = htsmsg_get_map(conf, "switch_conf")))
1620 idnode_load(&lse->lse_switch->ld_id, e);
1621
1622 /* Rotor */
1623 if (lse->lse_rotor && (e = htsmsg_get_map(conf, "rotor_conf")))
1624 idnode_load(&lse->lse_rotor->ld_id, e);
1625
1626 /* EN50494 */
1627 if (lse->lse_en50494 && (e = htsmsg_get_map(conf, "en50494_conf")))
1628 idnode_load(&lse->lse_en50494->ld_id, e);
1629 }
1630
1631 /* Create default LNB */
1632 if (!lse->lse_lnb)
1633 lse->lse_lnb = linuxdvb_lnb_create0(NULL, NULL, lse);
1634
1635 return lse;
1636 }
1637
1638 void
linuxdvb_satconf_delete(linuxdvb_satconf_t * ls,int delconf)1639 linuxdvb_satconf_delete ( linuxdvb_satconf_t *ls, int delconf )
1640 {
1641 linuxdvb_satconf_ele_t *lse, *nxt;
1642 char ubuf[UUID_HEX_SIZE];
1643 if (delconf)
1644 hts_settings_remove("input/linuxdvb/satconfs/%s", idnode_uuid_as_str(&ls->ls_id, ubuf));
1645 mtimer_disarm(&ls->ls_diseqc_timer);
1646 for (lse = TAILQ_FIRST(&ls->ls_elements); lse != NULL; lse = nxt) {
1647 nxt = TAILQ_NEXT(lse, lse_link);
1648 linuxdvb_satconf_ele_destroy(lse);
1649 }
1650 idnode_save_check(&ls->ls_id, 1);
1651 idnode_unlink(&ls->ls_id);
1652 free(ls);
1653 }
1654
1655 /******************************************************************************
1656 * DiseqC
1657 *****************************************************************************/
1658
1659 static const char *
linuxdvb_diseqc_class_get_title(idnode_t * o,const char * lang)1660 linuxdvb_diseqc_class_get_title ( idnode_t *o, const char *lang )
1661 {
1662 linuxdvb_diseqc_t *ld = (linuxdvb_diseqc_t*)o;
1663 return ld->ld_type;
1664 }
1665
1666 static void
linuxdvb_diseqc_class_changed(idnode_t * o)1667 linuxdvb_diseqc_class_changed ( idnode_t *o )
1668 {
1669 linuxdvb_diseqc_t *ld = (linuxdvb_diseqc_t*)o;
1670 if (ld->ld_satconf)
1671 linuxdvb_satconf_ele_class_changed(&ld->ld_satconf->lse_id);
1672 }
1673
1674 static const void *
linuxdvb_diseqc_class_active_get(void * obj)1675 linuxdvb_diseqc_class_active_get ( void *obj )
1676 {
1677 static int active;
1678 linuxdvb_diseqc_t *ld = obj;
1679 if (ld->ld_satconf)
1680 return linuxdvb_satconf_ele_class_active_get(ld->ld_satconf);
1681 active = 1;
1682 return &active;
1683 }
1684
1685 const idclass_t linuxdvb_diseqc_class =
1686 {
1687 .ic_class = "linuxdvb_diseqc",
1688 .ic_caption = N_("DiseqC"),
1689 .ic_event = "linuxdvb_diseqc",
1690 .ic_get_title = linuxdvb_diseqc_class_get_title,
1691 .ic_changed = linuxdvb_diseqc_class_changed,
1692 .ic_properties = (const property_t[]) {
1693 {
1694 .type = PT_BOOL,
1695 .id = "active",
1696 .name = N_("Active"),
1697 .opts = PO_RDONLY | PO_NOSAVE | PO_NOUI,
1698 .get = linuxdvb_diseqc_class_active_get,
1699 },
1700 {}
1701 }
1702 };
1703
1704 linuxdvb_diseqc_t *
linuxdvb_diseqc_create0(linuxdvb_diseqc_t * ld,const char * uuid,const idclass_t * idc,htsmsg_t * conf,const char * type,linuxdvb_satconf_ele_t * parent)1705 linuxdvb_diseqc_create0
1706 ( linuxdvb_diseqc_t *ld, const char *uuid, const idclass_t *idc,
1707 htsmsg_t *conf, const char *type, linuxdvb_satconf_ele_t *parent )
1708 {
1709 /* Insert */
1710 if (idnode_insert(&ld->ld_id, uuid, idc, 0)) {
1711 free(ld);
1712 return NULL;
1713 }
1714
1715 assert(type != NULL);
1716 ld->ld_type = strdup(type);
1717 ld->ld_satconf = parent;
1718
1719 /* Load config */
1720 if (conf)
1721 idnode_load(&ld->ld_id, conf);
1722
1723 return ld;
1724 }
1725
1726 void
linuxdvb_diseqc_destroy(linuxdvb_diseqc_t * ld)1727 linuxdvb_diseqc_destroy ( linuxdvb_diseqc_t *ld )
1728 {
1729 idnode_save_check(&ld->ld_id, 1);
1730 idnode_unlink(&ld->ld_id);
1731 free((void *)ld->ld_type);
1732 }
1733
1734 int
linuxdvb_diseqc_raw_send(int fd,int len,...)1735 linuxdvb_diseqc_raw_send
1736 (int fd, int len, ...)
1737 {
1738 int i;
1739 va_list ap;
1740 struct dvb_diseqc_master_cmd message;
1741 char buf[256];
1742 size_t c = 0;
1743
1744 /* Build message */
1745 message.msg_len = len;
1746 va_start(ap, len);
1747 for (i = 0; i < len; i++) {
1748 message.msg[i] = (uint8_t)va_arg(ap, int);
1749 if (tvhtrace_enabled())
1750 tvh_strlcatf(buf, sizeof(buf), c, "%02X ", message.msg[3 + i]);
1751 }
1752 va_end(ap);
1753
1754 if (tvhtrace_enabled())
1755 tvhtrace(LS_DISEQC, "sending raw diseqc (len %d) %s", len, buf);
1756
1757 /* Send */
1758 if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &message)) {
1759 tvherror(LS_DISEQC, "failed to send diseqc cmd (e=%s)", strerror(errno));
1760 return -1;
1761 }
1762 return 0;
1763 }
1764
1765 int
linuxdvb_diseqc_send(int fd,uint8_t framing,uint8_t addr,uint8_t cmd,int len,...)1766 linuxdvb_diseqc_send
1767 (int fd, uint8_t framing, uint8_t addr, uint8_t cmd, int len, ...)
1768 {
1769 int i;
1770 va_list ap;
1771 struct dvb_diseqc_master_cmd message;
1772 char buf[256];
1773 size_t c = 0;
1774
1775 /* Build message */
1776 message.msg_len = len + 3;
1777 message.msg[0] = framing;
1778 message.msg[1] = addr;
1779 message.msg[2] = cmd;
1780 va_start(ap, len);
1781 for (i = 0; i < len; i++) {
1782 message.msg[3 + i] = (uint8_t)va_arg(ap, int);
1783 if (tvhtrace_enabled())
1784 tvh_strlcatf(buf, sizeof(buf), c, "%02X ", message.msg[3 + i]);
1785 }
1786 va_end(ap);
1787
1788 if (tvhtrace_enabled())
1789 tvhtrace(LS_DISEQC, "sending diseqc (len %d) %02X %02X %02X %s",
1790 len + 3, framing, addr, cmd, buf);
1791
1792 /* Send */
1793 if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &message)) {
1794 tvherror(LS_DISEQC, "failed to send diseqc cmd (e=%s)", strerror(errno));
1795 return -1;
1796 }
1797 return 0;
1798 }
1799
1800 int
linuxdvb_diseqc_set_volt(linuxdvb_satconf_t * ls,int vol)1801 linuxdvb_diseqc_set_volt ( linuxdvb_satconf_t *ls, int vol )
1802 {
1803 /* Already set ? */
1804 if (vol >= 0 && ls->ls_last_vol == vol + 1)
1805 return 0;
1806 /* High voltage handling */
1807 if (ls->ls_lnb_highvol > 0) {
1808 int v = ls->ls_lnb_highvol > 1 ? 1 : 0;
1809 tvhtrace(LS_DISEQC, "set high voltage %d", v);
1810 if (ioctl(linuxdvb_satconf_fe_fd(ls), FE_ENABLE_HIGH_LNB_VOLTAGE, v))
1811 tvherror(LS_DISEQC, "failed to set high voltage %d (e=%s)", v, strerror(errno));
1812 }
1813 /* Set voltage */
1814 tvhtrace(LS_DISEQC, "set voltage %dV", vol ? (vol < 0 ? 0 : 18) : 13);
1815 if (ioctl(linuxdvb_satconf_fe_fd(ls), FE_SET_VOLTAGE,
1816 vol ? (vol < 0 ? SEC_VOLTAGE_OFF : SEC_VOLTAGE_18) : SEC_VOLTAGE_13)) {
1817 tvherror(LS_DISEQC, "failed to set voltage (e=%s)", strerror(errno));
1818 ls->ls_last_vol = 0;
1819 return -1;
1820 }
1821 if (vol >= 0)
1822 tvh_safe_usleep(15000);
1823 ls->ls_last_vol = vol ? (vol < 0 ? 0 : 2) : 1;
1824 return 0;
1825 }
1826
1827 /******************************************************************************
1828 * Editor Configuration
1829 *
1830 * vim:sts=2:ts=2:sw=2:et
1831 *****************************************************************************/
1832