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