1 /*
2 * Tvheadend - Linux DVB DiseqC switch
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 #include "hts_strtab.h"
24
25 #include <sys/ioctl.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <assert.h>
31 #include <linux/dvb/dmx.h>
32 #include <linux/dvb/frontend.h>
33
34 /* **************************************************************************
35 * Class definition
36 * *************************************************************************/
37
38 typedef struct linuxdvb_switch
39 {
40 linuxdvb_diseqc_t;
41
42 /* Port settings */
43 int ls_toneburst;
44 int ls_committed;
45 int ls_uncommitted;
46 int ls_uncommitted_first;
47 uint32_t ls_powerup_time; /* in ms */
48 uint32_t ls_sleep_time; /* in ms */
49
50 } linuxdvb_switch_t;
51
52 static htsmsg_t *
linuxdvb_switch_class_committed_list(void * o,const char * lang)53 linuxdvb_switch_class_committed_list ( void *o, const char *lang )
54 {
55 static const struct strtab tab[] = {
56 { N_("NONE"), -1 },
57 { N_("AA"), 0 },
58 { N_("AB"), 1 },
59 { N_("BA"), 2 },
60 { N_("BB"), 3 },
61 };
62 return strtab2htsmsg(tab, 1, lang);
63 }
64
65 static htsmsg_t *
linuxdvb_switch_class_uncommitted_list(void * o,const char * lang)66 linuxdvb_switch_class_uncommitted_list ( void *o, const char *lang )
67 {
68 static const struct strtab tab[] = {
69 { N_("NONE"), -1 },
70 { N_( "0"), 0 },
71 { N_( "1"), 1 },
72 { N_( "2"), 2 },
73 { N_( "3"), 3 },
74 { N_( "4"), 4 },
75 { N_( "5"), 5 },
76 { N_( "6"), 6 },
77 { N_( "7"), 7 },
78 { N_( "8"), 8 },
79 { N_( "9"), 9 },
80 { N_("10"), 10 },
81 { N_("11"), 11 },
82 { N_("12"), 12 },
83 { N_("13"), 13 },
84 { N_("14"), 14 },
85 { N_("15"), 15 },
86 };
87 return strtab2htsmsg(tab, 1, lang);
88 }
89
90 static htsmsg_t *
linuxdvb_switch_class_toneburst_list(void * o,const char * lang)91 linuxdvb_switch_class_toneburst_list ( void *o, const char *lang )
92 {
93 static const struct strtab tab[] = {
94 { N_("NONE"), -1 },
95 { N_("A"), 0 },
96 { N_("B"), 1 },
97 };
98 return strtab2htsmsg(tab, 1, lang);
99 }
100
101 static const char *
linuxdvb_switch_class_get_title(idnode_t * o,const char * lang)102 linuxdvb_switch_class_get_title ( idnode_t *o, const char *lang )
103 {
104 static char buf[256];
105 linuxdvb_diseqc_t *ld = (linuxdvb_diseqc_t*)o;
106 snprintf(buf, sizeof(buf), tvh_gettext_lang(lang, N_("Switch: %s")), ld->ld_type);
107 return buf;
108 }
109
110 extern const idclass_t linuxdvb_diseqc_class;
111
112 CLASS_DOC(linuxdvb_satconf)
113
114 const idclass_t linuxdvb_switch_class =
115 {
116 .ic_super = &linuxdvb_diseqc_class,
117 .ic_class = "linuxdvb_switch",
118 .ic_caption = N_("TV Adapters - SatConfig - DiseqC Switch"),
119 .ic_doc = tvh_doc_linuxdvb_satconf_class,
120 .ic_get_title = linuxdvb_switch_class_get_title,
121 .ic_properties = (const property_t[]) {
122 {
123 .type = PT_INT,
124 .id = "committed",
125 .name = N_("Committed"),
126 .off = offsetof(linuxdvb_switch_t, ls_committed),
127 .list = linuxdvb_switch_class_committed_list
128 },
129 {
130 .type = PT_INT,
131 .id = "uncommitted",
132 .name = N_("Uncommitted"),
133 .off = offsetof(linuxdvb_switch_t, ls_uncommitted),
134 .list = linuxdvb_switch_class_uncommitted_list
135 },
136 {
137 .type = PT_INT,
138 .id = "toneburst",
139 .name = N_("Tone burst"),
140 .off = offsetof(linuxdvb_switch_t, ls_toneburst),
141 .list = linuxdvb_switch_class_toneburst_list
142 },
143 {
144 .type = PT_BOOL,
145 .id = "preferun",
146 .name = N_("Uncommitted first"),
147 .off = offsetof(linuxdvb_switch_t, ls_uncommitted_first),
148 },
149 {
150 .type = PT_U32,
151 .id = "poweruptime",
152 .name = N_("Power-up time (ms) (15-200)"),
153 .off = offsetof(linuxdvb_switch_t, ls_powerup_time),
154 .def.u32 = 100,
155 },
156 {
157 .type = PT_U32,
158 .id = "sleeptime",
159 .name = N_("Command delay time (ms) (10-200)"),
160 .off = offsetof(linuxdvb_switch_t, ls_sleep_time),
161 .def.u32 = 25
162 },
163 {}
164 }
165 };
166
167 /* **************************************************************************
168 * Class methods
169 * *************************************************************************/
170
171 static int
linuxdvb_switch_tune(linuxdvb_diseqc_t * ld,dvb_mux_t * lm,linuxdvb_satconf_t * lsp,linuxdvb_satconf_ele_t * sc,int vol,int pol,int band,int freq)172 linuxdvb_switch_tune
173 ( linuxdvb_diseqc_t *ld, dvb_mux_t *lm, linuxdvb_satconf_t *lsp,
174 linuxdvb_satconf_ele_t *sc, int vol, int pol, int band, int freq )
175 {
176 int i, com, r1 = 0, r2 = 0, slp;
177 int fd = linuxdvb_satconf_fe_fd(lsp);
178 linuxdvb_switch_t *ls = (linuxdvb_switch_t*)ld;
179
180 if (lsp->ls_diseqc_full || lsp->ls_last_switch != sc ||
181 (ls->ls_committed >= 0 &&
182 (pol + 1 != lsp->ls_last_switch_pol ||
183 band + 1 != lsp->ls_last_switch_band))) {
184
185 lsp->ls_last_switch = NULL;
186
187 if (linuxdvb_satconf_start(lsp, MINMAX(ls->ls_powerup_time, 15, 200), pol))
188 return -1;
189
190 com = 0xF0 | (ls->ls_committed << 2) | (pol << 1) | band;
191 slp = MINMAX(ls->ls_sleep_time, 25, 200) * 1000;
192
193 /* Repeats */
194 for (i = 0; i <= lsp->ls_diseqc_repeats; i++) {
195
196 if (ls->ls_uncommitted_first)
197 /* Uncommitted */
198 if (ls->ls_uncommitted >= 0) {
199 if (linuxdvb_diseqc_send(fd, 0xE0 | r2, 0x10, 0x39, 1,
200 0xF0 | ls->ls_uncommitted))
201 return -1;
202 tvh_safe_usleep(slp);
203 }
204
205 /* Committed */
206 if (ls->ls_committed >= 0) {
207 if (linuxdvb_diseqc_send(fd, 0xE0 | r1, 0x10, 0x38, 1, com))
208 return -1;
209 tvh_safe_usleep(slp);
210 }
211
212 if (!ls->ls_uncommitted_first) {
213 /* Uncommitted */
214 if (ls->ls_uncommitted >= 0) {
215 if (linuxdvb_diseqc_send(fd, 0xE0 | r2, 0x10, 0x39, 1,
216 0xF0 | ls->ls_uncommitted))
217 return -1;
218 tvh_safe_usleep(slp);
219 }
220 }
221
222 /* repeat flag */
223 r1 = r2 = 1;
224 }
225
226 lsp->ls_last_switch = sc;
227 lsp->ls_last_switch_pol = pol + 1;
228 lsp->ls_last_switch_band = band + 1;
229
230 /* port was changed, new LNB has not received toneburst yet */
231 lsp->ls_last_toneburst = 0;
232 }
233
234 /* Tone burst */
235 if (ls->ls_toneburst >= 0 &&
236 (lsp->ls_diseqc_full || lsp->ls_last_toneburst != ls->ls_toneburst + 1)) {
237
238 if (linuxdvb_satconf_start(lsp, MINMAX(ls->ls_powerup_time, 15, 200), vol))
239 return -1;
240
241 lsp->ls_last_toneburst = 0;
242 tvhtrace(LS_DISEQC, "toneburst %s", ls->ls_toneburst ? "B" : "A");
243 if (ioctl(fd, FE_DISEQC_SEND_BURST,
244 ls->ls_toneburst ? SEC_MINI_B : SEC_MINI_A)) {
245 tvherror(LS_DISEQC, "failed to set toneburst (e=%s)", strerror(errno));
246 return -1;
247 }
248 lsp->ls_last_toneburst = ls->ls_toneburst + 1;
249 }
250
251 return 0;
252 }
253
254 /* **************************************************************************
255 * Create / Config
256 * *************************************************************************/
257
258 htsmsg_t *
linuxdvb_switch_list(void * o,const char * lang)259 linuxdvb_switch_list ( void *o, const char *lang )
260 {
261 htsmsg_t *m = htsmsg_create_list();
262 htsmsg_add_msg(m, NULL, htsmsg_create_key_val("", tvh_gettext_lang(lang, N_("None"))));
263 htsmsg_add_msg(m, NULL, htsmsg_create_key_val("Generic", tvh_gettext_lang(lang, N_("Generic"))));
264 return m;
265 }
266
267 linuxdvb_diseqc_t *
linuxdvb_switch_create0(const char * name,htsmsg_t * conf,linuxdvb_satconf_ele_t * ls,int c,int u)268 linuxdvb_switch_create0
269 ( const char *name, htsmsg_t *conf, linuxdvb_satconf_ele_t *ls, int c, int u )
270 {
271 linuxdvb_switch_t *ld = NULL;
272 if (!strcmp(name ?: "", "Generic")) {
273 ld = (linuxdvb_switch_t*)linuxdvb_diseqc_create(linuxdvb_switch, NULL, conf, "Generic", ls);
274 if (ld) {
275 ld->ld_tune = linuxdvb_switch_tune;
276 if (!conf) {
277 ld->ls_committed = -1;
278 ld->ls_uncommitted = -1;
279 ld->ls_toneburst = -1;
280 if (c >= 0) {
281 ld->ls_committed = c;
282 ld->ls_toneburst = c % 2;
283 }
284 if (u >= 0)
285 ld->ls_uncommitted = u;
286 }
287 if (ld->ls_powerup_time == 0)
288 ld->ls_powerup_time = 100;
289 if (ld->ls_sleep_time == 0)
290 ld->ls_sleep_time = 25;
291 }
292 }
293
294 return (linuxdvb_diseqc_t*)ld;
295 }
296
297 void
linuxdvb_switch_destroy(linuxdvb_diseqc_t * ld)298 linuxdvb_switch_destroy ( linuxdvb_diseqc_t *ld )
299 {
300 linuxdvb_diseqc_destroy(ld);
301 free(ld);
302 }
303
304 /******************************************************************************
305 * Editor Configuration
306 *
307 * vim:sts=2:ts=2:sw=2:et
308 *****************************************************************************/
309