1 /*
2 * Tvheadend - Linux DVB LNB config
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 <fcntl.h>
29 #include <assert.h>
30 #include <linux/dvb/dmx.h>
31
32 /* **************************************************************************
33 * Class definition
34 * *************************************************************************/
35
36 typedef struct linuxdvb_lnb_conf
37 {
38 linuxdvb_lnb_t;
39
40 /* Freq control */
41 int lnb_low;
42 int lnb_high;
43 int lnb_switch;
44 } linuxdvb_lnb_conf_t;
45
46 static const char *
linuxdvb_lnb_class_get_title(idnode_t * o,const char * lang)47 linuxdvb_lnb_class_get_title ( idnode_t *o, const char *lang )
48 {
49 static char buf[256];
50 linuxdvb_diseqc_t *ld = (linuxdvb_diseqc_t*)o;
51 snprintf(buf, sizeof(buf), "LNB: %s", ld->ld_type);
52 return buf;
53 }
54
55 extern const idclass_t linuxdvb_diseqc_class;
56
57 const idclass_t linuxdvb_lnb_class =
58 {
59 .ic_super = &linuxdvb_diseqc_class,
60 .ic_class = "linuxdvb_lnb_basic",
61 .ic_caption = N_("LNB"),
62 .ic_get_title = linuxdvb_lnb_class_get_title,
63 .ic_properties = (const property_t[]) {
64 {
65 .type = PT_INT,
66 .id = "lfo",
67 .name = N_("Low frequency offset"),
68 .opts = PO_RDONLY | PO_NOSAVE,
69 .off = offsetof(linuxdvb_lnb_conf_t, lnb_low),
70 },
71 {
72 .type = PT_INT,
73 .id = "hfo",
74 .name = N_("High frequency offset"),
75 .opts = PO_RDONLY | PO_NOSAVE,
76 .off = offsetof(linuxdvb_lnb_conf_t, lnb_high),
77 },
78 {
79 .type = PT_INT,
80 .id = "sfo",
81 .name = N_("Switch frequency offset"),
82 .opts = PO_RDONLY | PO_NOSAVE,
83 .off = offsetof(linuxdvb_lnb_conf_t, lnb_switch),
84 },
85 {}
86 }
87 };
88
89 /* **************************************************************************
90 * Control functions
91 * *************************************************************************/
92
93 /*
94 * Standard freq switched LNB
95 */
96
97 static uint32_t
linuxdvb_lnb_standard_freq(linuxdvb_lnb_t * l,dvb_mux_t * lm)98 linuxdvb_lnb_standard_freq
99 ( linuxdvb_lnb_t *l, dvb_mux_t *lm )
100 {
101 linuxdvb_lnb_conf_t *lnb = (linuxdvb_lnb_conf_t*)l;
102 int32_t f = (int32_t)lm->lm_tuning.dmc_fe_freq;
103 if (lnb->lnb_switch && f > lnb->lnb_switch)
104 f -= lnb->lnb_high;
105 else
106 f -= lnb->lnb_low;
107 return (uint32_t)abs(f);
108 }
109
110 static int
linuxdvb_lnb_bandstack_match(linuxdvb_lnb_t * l,dvb_mux_t * lm1,dvb_mux_t * lm2)111 linuxdvb_lnb_bandstack_match
112 ( linuxdvb_lnb_t *l, dvb_mux_t *lm1, dvb_mux_t *lm2 )
113 {
114 /* everything is in one cable */
115 return 1;
116 }
117
118 static int
linuxdvb_lnb_standard_match(linuxdvb_lnb_t * l,dvb_mux_t * lm1,dvb_mux_t * lm2)119 linuxdvb_lnb_standard_match
120 ( linuxdvb_lnb_t *l, dvb_mux_t *lm1, dvb_mux_t *lm2 )
121 {
122 linuxdvb_lnb_conf_t *lnb = (linuxdvb_lnb_conf_t*)l;
123 dvb_mux_conf_t *dmc1 = &lm1->lm_tuning;
124 dvb_mux_conf_t *dmc2 = &lm2->lm_tuning;
125
126 if (lnb->lnb_switch) {
127 uint32_t hi1 = dmc1->dmc_fe_freq > lnb->lnb_switch;
128 uint32_t hi2 = dmc2->dmc_fe_freq > lnb->lnb_switch;
129 if (hi1 != hi2)
130 return 0;
131 }
132 if (dmc1->u.dmc_fe_qpsk.polarisation != dmc2->u.dmc_fe_qpsk.polarisation)
133 return 0;
134 return 1;
135 }
136
137 static int
linuxdvb_lnb_standard_band(linuxdvb_lnb_t * l,dvb_mux_t * lm)138 linuxdvb_lnb_standard_band
139 ( linuxdvb_lnb_t *l, dvb_mux_t *lm )
140 {
141 linuxdvb_lnb_conf_t *lnb = (linuxdvb_lnb_conf_t*)l;
142 uint32_t f = lm->lm_tuning.dmc_fe_freq;
143 return (lnb->lnb_switch && f > lnb->lnb_switch);
144 }
145
146 static int
linuxdvb_lnb_standard_pol(linuxdvb_lnb_t * l,dvb_mux_t * lm)147 linuxdvb_lnb_standard_pol
148 ( linuxdvb_lnb_t *l, dvb_mux_t *lm )
149 {
150 dvb_mux_conf_t *dmc = &lm->lm_tuning;
151 return dmc->u.dmc_fe_qpsk.polarisation == DVB_POLARISATION_HORIZONTAL ||
152 dmc->u.dmc_fe_qpsk.polarisation == DVB_POLARISATION_CIRCULAR_LEFT;
153 }
154
155 static int
linuxdvb_lnb_inverted_pol(linuxdvb_lnb_t * l,dvb_mux_t * lm)156 linuxdvb_lnb_inverted_pol
157 ( linuxdvb_lnb_t *l, dvb_mux_t *lm )
158 {
159 return !linuxdvb_lnb_standard_pol(l, lm);
160 }
161
162 static int
linuxdvb_lnb_standard_tune(linuxdvb_diseqc_t * ld,dvb_mux_t * lm,linuxdvb_satconf_t * lsp,linuxdvb_satconf_ele_t * ls,int vol,int pol,int band,int freq)163 linuxdvb_lnb_standard_tune
164 ( linuxdvb_diseqc_t *ld, dvb_mux_t *lm,
165 linuxdvb_satconf_t *lsp, linuxdvb_satconf_ele_t *ls,
166 int vol, int pol, int band, int freq )
167 {
168 return linuxdvb_diseqc_set_volt(ls->lse_parent, vol);
169 }
170
171 /*
172 * Bandstacked polarity switch LNB
173 */
174
175 static uint32_t
linuxdvb_lnb_bandstack_freq(linuxdvb_lnb_t * l,dvb_mux_t * lm)176 linuxdvb_lnb_bandstack_freq
177 ( linuxdvb_lnb_t *l, dvb_mux_t *lm )
178 {
179 linuxdvb_lnb_conf_t *lnb = (linuxdvb_lnb_conf_t*)l;
180 int32_t f = (int32_t)lm->lm_tuning.dmc_fe_freq;
181 dvb_mux_conf_t *dmc = &lm->lm_tuning;
182 int pol = dmc->u.dmc_fe_qpsk.polarisation == DVB_POLARISATION_HORIZONTAL ||
183 dmc->u.dmc_fe_qpsk.polarisation == DVB_POLARISATION_CIRCULAR_LEFT;
184 if (pol)
185 f -= lnb->lnb_high;
186 else
187 f -= lnb->lnb_low;
188 return (uint32_t)abs(f);
189 }
190
191 static int
linuxdvb_lnb_bandstack_band(linuxdvb_lnb_t * l,dvb_mux_t * lm)192 linuxdvb_lnb_bandstack_band
193 ( linuxdvb_lnb_t *l, dvb_mux_t *lm )
194 {
195 dvb_mux_conf_t *dmc = &lm->lm_tuning;
196 int pol = dmc->u.dmc_fe_qpsk.polarisation == DVB_POLARISATION_HORIZONTAL ||
197 dmc->u.dmc_fe_qpsk.polarisation == DVB_POLARISATION_CIRCULAR_LEFT;
198 return pol;
199 }
200
201 static int
linuxdvb_lnb_bandstack_pol(linuxdvb_lnb_t * l,dvb_mux_t * lm)202 linuxdvb_lnb_bandstack_pol
203 ( linuxdvb_lnb_t *l, dvb_mux_t *lm )
204 {
205 return 0;
206 }
207
208 /* **************************************************************************
209 * Static list
210 * *************************************************************************/
211
212 linuxdvb_lnb_conf_t linuxdvb_lnb_all[] = {
213 {
214 { {
215 .ld_type = "Universal",
216 .ld_tune = linuxdvb_lnb_standard_tune,
217 },
218 .lnb_freq = linuxdvb_lnb_standard_freq,
219 .lnb_match = linuxdvb_lnb_standard_match,
220 .lnb_band = linuxdvb_lnb_standard_band,
221 .lnb_pol = linuxdvb_lnb_standard_pol,
222 },
223 .lnb_low = 9750000,
224 .lnb_high = 10600000,
225 .lnb_switch = 11700000,
226 },
227 {
228 { {
229 .ld_type = "Standard",
230 .ld_tune = linuxdvb_lnb_standard_tune,
231 },
232 .lnb_freq = linuxdvb_lnb_standard_freq,
233 .lnb_match = linuxdvb_lnb_standard_match,
234 .lnb_band = linuxdvb_lnb_standard_band,
235 .lnb_pol = linuxdvb_lnb_standard_pol,
236 },
237 .lnb_low = 10000000,
238 .lnb_high = 0,
239 .lnb_switch = 0,
240 },
241 {
242 { {
243 .ld_type = "Enhanced",
244 .ld_tune = linuxdvb_lnb_standard_tune,
245 },
246 .lnb_freq = linuxdvb_lnb_standard_freq,
247 .lnb_match = linuxdvb_lnb_standard_match,
248 .lnb_band = linuxdvb_lnb_standard_band,
249 .lnb_pol = linuxdvb_lnb_standard_pol,
250 },
251 .lnb_low = 9750000,
252 .lnb_high = 0,
253 .lnb_switch = 0,
254 },
255 {
256 { {
257 .ld_type = "C-Band",
258 .ld_tune = linuxdvb_lnb_standard_tune,
259 },
260 .lnb_freq = linuxdvb_lnb_standard_freq,
261 .lnb_match = linuxdvb_lnb_standard_match,
262 .lnb_band = linuxdvb_lnb_standard_band,
263 .lnb_pol = linuxdvb_lnb_standard_pol,
264 },
265 .lnb_low = 5150000,
266 .lnb_high = 0,
267 .lnb_switch = 0,
268 },
269 {
270 { {
271 .ld_type = "C-Band (bandstack)",
272 .ld_tune = linuxdvb_lnb_standard_tune,
273 },
274 .lnb_freq = linuxdvb_lnb_bandstack_freq,
275 .lnb_match = linuxdvb_lnb_bandstack_match,
276 .lnb_band = linuxdvb_lnb_bandstack_band,
277 .lnb_pol = linuxdvb_lnb_bandstack_pol,
278 },
279 .lnb_low = 5150000,
280 .lnb_high = 5750000,
281 .lnb_switch = 0,
282 },
283 {
284 { {
285 .ld_type = "Ku 10750",
286 .ld_tune = linuxdvb_lnb_standard_tune,
287 },
288 .lnb_freq = linuxdvb_lnb_standard_freq,
289 .lnb_match = linuxdvb_lnb_standard_match,
290 .lnb_band = linuxdvb_lnb_standard_band,
291 .lnb_pol = linuxdvb_lnb_standard_pol,
292 },
293 .lnb_low = 10750000,
294 .lnb_high = 0,
295 .lnb_switch = 0,
296 },
297 {
298 { {
299 .ld_type = "Ku 10750 (Hi-Band)",
300 .ld_tune = linuxdvb_lnb_standard_tune,
301 },
302 .lnb_freq = linuxdvb_lnb_standard_freq,
303 .lnb_match = linuxdvb_lnb_standard_match,
304 .lnb_band = linuxdvb_lnb_standard_band,
305 .lnb_pol = linuxdvb_lnb_standard_pol,
306 },
307 .lnb_low = 10750000,
308 .lnb_high = 10750000,
309 .lnb_switch = 10750000,
310 },
311 {
312 { {
313 .ld_type = "Ku 10750 (Hi-Band, Inverted-Polar.)",
314 .ld_tune = linuxdvb_lnb_standard_tune,
315 },
316 .lnb_freq = linuxdvb_lnb_standard_freq,
317 .lnb_match = linuxdvb_lnb_standard_match,
318 .lnb_band = linuxdvb_lnb_standard_band,
319 .lnb_pol = linuxdvb_lnb_inverted_pol,
320 },
321 .lnb_low = 10750000,
322 .lnb_high = 10750000,
323 .lnb_switch = 10750000,
324 },
325 {
326 { {
327 .ld_type = "Ku 11300",
328 .ld_tune = linuxdvb_lnb_standard_tune,
329 },
330 .lnb_freq = linuxdvb_lnb_standard_freq,
331 .lnb_match = linuxdvb_lnb_standard_match,
332 .lnb_band = linuxdvb_lnb_standard_band,
333 .lnb_pol = linuxdvb_lnb_standard_pol,
334 },
335 .lnb_low = 11300000,
336 .lnb_high = 0,
337 .lnb_switch = 0,
338 },
339 {
340 { {
341 .ld_type = "Ku 11300 (Hi-Band)",
342 .ld_tune = linuxdvb_lnb_standard_tune,
343 },
344 .lnb_freq = linuxdvb_lnb_standard_freq,
345 .lnb_match = linuxdvb_lnb_standard_match,
346 .lnb_band = linuxdvb_lnb_standard_band,
347 .lnb_pol = linuxdvb_lnb_standard_pol,
348 },
349 .lnb_low = 11300000,
350 .lnb_high = 11300000,
351 .lnb_switch = 11300000,
352 },
353 {
354 { {
355 .ld_type = "C 5150/Ku 10750 (22kHz switch)",
356 .ld_tune = linuxdvb_lnb_standard_tune,
357 },
358 .lnb_freq = linuxdvb_lnb_standard_freq,
359 .lnb_band = linuxdvb_lnb_standard_band,
360 .lnb_pol = linuxdvb_lnb_standard_pol,
361 },
362 .lnb_low = 5150000,
363 .lnb_high = 10750000,
364 .lnb_switch = 11700000, /* 10750 + 950 (bottom of the receiver range 950Mhz-2150Mhz) */
365 },
366 {
367 { {
368 .ld_type = "DBS",
369 .ld_tune = linuxdvb_lnb_standard_tune,
370 },
371 .lnb_freq = linuxdvb_lnb_standard_freq,
372 .lnb_match = linuxdvb_lnb_standard_match,
373 .lnb_band = linuxdvb_lnb_standard_band,
374 .lnb_pol = linuxdvb_lnb_standard_pol,
375 },
376 .lnb_low = 11250000,
377 .lnb_high = 0,
378 .lnb_switch = 0,
379 },
380 {
381 { {
382 .ld_type = "DBS Bandstack",
383 .ld_tune = linuxdvb_lnb_standard_tune,
384 },
385 .lnb_freq = linuxdvb_lnb_bandstack_freq,
386 .lnb_match = linuxdvb_lnb_bandstack_match,
387 .lnb_band = linuxdvb_lnb_bandstack_band,
388 .lnb_pol = linuxdvb_lnb_bandstack_pol,
389 },
390 .lnb_low = 11250000,
391 .lnb_high = 14350000,
392 .lnb_switch = 0,
393 },
394 {
395 { {
396 .ld_type = "Ku 10700 (Australia)",
397 .ld_tune = linuxdvb_lnb_standard_tune,
398 },
399 .lnb_freq = linuxdvb_lnb_standard_freq,
400 .lnb_match = linuxdvb_lnb_standard_match,
401 .lnb_band = linuxdvb_lnb_standard_band,
402 .lnb_pol = linuxdvb_lnb_standard_pol,
403 },
404 .lnb_low = 10700000,
405 .lnb_high = 10700000,
406 .lnb_switch = 11800000,
407 },
408 };
409
410 /* **************************************************************************
411 * Create / Config
412 * *************************************************************************/
413
414 htsmsg_t *
linuxdvb_lnb_list(void * o,const char * lang)415 linuxdvb_lnb_list ( void *o, const char *lang )
416 {
417 int i;
418 htsmsg_t *m = htsmsg_create_list();
419 for (i = 0; i < ARRAY_SIZE(linuxdvb_lnb_all); i++)
420 htsmsg_add_str(m, NULL, linuxdvb_lnb_all[i].ld_type);
421 return m;
422 }
423
424 linuxdvb_lnb_t *
linuxdvb_lnb_create0(const char * name,htsmsg_t * conf,linuxdvb_satconf_ele_t * ls)425 linuxdvb_lnb_create0
426 ( const char *name, htsmsg_t *conf, linuxdvb_satconf_ele_t *ls )
427 {
428 linuxdvb_lnb_conf_t *lsc = &linuxdvb_lnb_all[0], *lsc2;
429 int i;
430
431 /* Find */
432 if (name) {
433 for (i = 0; i < ARRAY_SIZE(linuxdvb_lnb_all); i++)
434 if (!strcmp(linuxdvb_lnb_all[i].ld_type, name)) {
435 lsc = &linuxdvb_lnb_all[i];
436 break;
437 }
438 }
439
440 lsc2 = malloc(sizeof(linuxdvb_lnb_conf_t));
441 *lsc2 = *lsc;
442 return (linuxdvb_lnb_t *)
443 linuxdvb_diseqc_create0((linuxdvb_diseqc_t *)lsc2,
444 NULL, &linuxdvb_lnb_class,
445 conf, lsc->ld_type, ls);
446 }
447
448 void
linuxdvb_lnb_destroy(linuxdvb_lnb_t * lnb)449 linuxdvb_lnb_destroy ( linuxdvb_lnb_t *lnb )
450 {
451 linuxdvb_diseqc_destroy((linuxdvb_diseqc_t *)lnb);
452 free(lnb);
453 }
454
455 /******************************************************************************
456 * Editor Configuration
457 *
458 * vim:sts=2:ts=2:sw=2:et
459 *****************************************************************************/
460