1
|
#include <stdio.h>
|
2
|
#include <fcntl.h>
|
3
|
#include <memory.h>
|
4
|
#include <time.h>
|
5
|
#include <stdint.h>
|
6
|
#include <sys/ioctl.h>
|
7
|
#include <linux/dvb/frontend.h>
|
8
|
#include <linux/dvb/dmx.h>
|
9
|
|
10
|
#define LOWVAL 9750000
|
11
|
#define HIGHVAL 10600000
|
12
|
#define SWITCHVAL 11700000
|
13
|
|
14
|
#define BUFSIZE 4096
|
15
|
|
16
|
struct adapter_struct {
|
17
|
const char *fe_name;
|
18
|
const char *dvr_name;
|
19
|
const char *dmx_name;
|
20
|
int fe_fd;
|
21
|
int dvr_fd;
|
22
|
int dmx_fd;
|
23
|
unsigned char buffer[BUFSIZE];
|
24
|
unsigned long byte_counter;
|
25
|
};
|
26
|
|
27
|
struct adapter_struct adapter[2] = {
|
28
|
{
|
29
|
.fe_name = "/dev/dvb/adapter0/frontend0",
|
30
|
.dvr_name = "/dev/dvb/adapter0/dvr0",
|
31
|
.dmx_name = "/dev/dvb/adapter0/demux0"
|
32
|
},
|
33
|
{
|
34
|
.fe_name = "/dev/dvb/adapter1/frontend0",
|
35
|
.dvr_name = "/dev/dvb/adapter1/dvr0",
|
36
|
.dmx_name = "/dev/dvb/adapter1/demux0"
|
37
|
}
|
38
|
};
|
39
|
|
40
|
struct channel_struct {
|
41
|
const unsigned int frontend;
|
42
|
const unsigned int demux;
|
43
|
const unsigned int sat_no;
|
44
|
const unsigned int freq;
|
45
|
const unsigned int pol;
|
46
|
const unsigned int sr;
|
47
|
const unsigned int vpid;
|
48
|
const unsigned int apid;
|
49
|
const int sid;
|
50
|
const unsigned int delivery;
|
51
|
const int modulation;
|
52
|
const int fec;
|
53
|
const int rolloff;
|
54
|
};
|
55
|
|
56
|
const struct channel_struct svt1_hd = {
|
57
|
.frontend = 0,
|
58
|
.demux = 0,
|
59
|
.sat_no = 1,
|
60
|
.freq = 10903000,
|
61
|
.pol = 1,
|
62
|
.sr = 25000000,
|
63
|
.vpid = 512,
|
64
|
.apid = 640,
|
65
|
.sid = 1406,
|
66
|
.delivery = 6,
|
67
|
.modulation = 0,
|
68
|
.fec = 9,
|
69
|
.rolloff = 0,
|
70
|
};
|
71
|
|
72
|
const struct channel_struct viasat_hockey = {
|
73
|
.frontend = 0,
|
74
|
.demux = 0,
|
75
|
.sat_no = 0,
|
76
|
.freq = 11977000,
|
77
|
.pol = 1,
|
78
|
.sr = 27500000,
|
79
|
.vpid = 2141,
|
80
|
.apid = 2142,
|
81
|
.sid = 2140,
|
82
|
.delivery = 5,
|
83
|
.modulation = 0,
|
84
|
.fec = 9,
|
85
|
.rolloff = 0,
|
86
|
};
|
87
|
|
88
|
const struct channel_struct *channel[3] = {
|
89
|
&svt1_hd,
|
90
|
&viasat_hockey
|
91
|
};
|
92
|
|
93
|
struct diseqc_cmd {
|
94
|
struct dvb_diseqc_master_cmd cmd;
|
95
|
uint32_t wait;
|
96
|
};
|
97
|
|
98
|
void diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd,
|
99
|
fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b)
|
100
|
{
|
101
|
if (ioctl(fd, FE_SET_TONE, SEC_TONE_OFF) == -1)
|
102
|
perror("FE_SET_TONE failed");
|
103
|
if (ioctl(fd, FE_SET_VOLTAGE, v) == -1)
|
104
|
perror("FE_SET_VOLTAGE failed");
|
105
|
usleep(15 * 1000);
|
106
|
if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd) == -1)
|
107
|
perror("FE_DISEQC_SEND_MASTER_CMD failed");
|
108
|
usleep(cmd->wait * 1000);
|
109
|
usleep(15 * 1000);
|
110
|
if (ioctl(fd, FE_DISEQC_SEND_BURST, b) == -1)
|
111
|
perror("FE_DISEQC_SEND_BURST failed");
|
112
|
usleep(15 * 1000);
|
113
|
if (ioctl(fd, FE_SET_TONE, t) == -1)
|
114
|
perror("FE_SET_TONE failed");
|
115
|
}
|
116
|
|
117
|
/* digital satellite equipment control,
|
118
|
* specification is available from http://www.eutelsat.com/
|
119
|
*/
|
120
|
int diseqc(int secfd, int sat_no, int pol_vert, int hi_band)
|
121
|
{
|
122
|
struct diseqc_cmd cmd =
|
123
|
{ {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
|
124
|
|
125
|
/**
|
126
|
* param: high nibble: reset bits, low nibble set bits,
|
127
|
* bits are: option, position, polarizaion, band
|
128
|
*/
|
129
|
cmd.cmd.msg[3] =
|
130
|
0xf0 | (((sat_no * 4) & 0x0f) | (hi_band ? 1 : 0) | (pol_vert ? 0 : 2));
|
131
|
|
132
|
diseqc_send_msg(secfd, pol_vert ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18,
|
133
|
&cmd, hi_band ? SEC_TONE_ON : SEC_TONE_OFF,
|
134
|
(sat_no / 4) % 2 ? SEC_MINI_B : SEC_MINI_A);
|
135
|
|
136
|
return 1; //TRUE
|
137
|
}
|
138
|
|
139
|
int do_tune(int fefd, unsigned int ifreq, unsigned int sr, enum fe_delivery_system delsys,
|
140
|
int modulation, int fec, int rolloff)
|
141
|
{
|
142
|
struct dvb_frontend_event ev;
|
143
|
struct dtv_property p[] = {
|
144
|
{ .cmd = DTV_DELIVERY_SYSTEM, .u.data = delsys },
|
145
|
{ .cmd = DTV_FREQUENCY, .u.data = ifreq },
|
146
|
{ .cmd = DTV_MODULATION, .u.data = modulation },
|
147
|
{ .cmd = DTV_SYMBOL_RATE, .u.data = sr },
|
148
|
{ .cmd = DTV_INNER_FEC, .u.data = fec },
|
149
|
{ .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
|
150
|
{ .cmd = DTV_ROLLOFF, .u.data = rolloff },
|
151
|
{ .cmd = DTV_PILOT, .u.data = PILOT_AUTO },
|
152
|
{ .cmd = DTV_TUNE },
|
153
|
};
|
154
|
struct dtv_properties cmdseq = {
|
155
|
.num = 9,
|
156
|
.props = p
|
157
|
};
|
158
|
|
159
|
/* discard stale QPSK events */
|
160
|
while (1) {
|
161
|
if (ioctl(fefd, FE_GET_EVENT, &ev) == -1)
|
162
|
break;
|
163
|
}
|
164
|
|
165
|
if ((ioctl(fefd, FE_SET_PROPERTY, &cmdseq)) == -1) {
|
166
|
perror("FE_SET_PROPERTY failed");
|
167
|
return 0; //FALSE
|
168
|
}
|
169
|
|
170
|
return 1; //TRUE
|
171
|
}
|
172
|
|
173
|
void print_frontend_status(struct adapter_struct *a)
|
174
|
{
|
175
|
fe_status_t status;
|
176
|
uint16_t snr, signal;
|
177
|
uint32_t ber, uncorrected_blocks;
|
178
|
int timeout = 0;
|
179
|
|
180
|
if (ioctl(a->fe_fd, FE_READ_STATUS, &status) == -1)
|
181
|
perror("FE_READ_STATUS failed");
|
182
|
if (ioctl(a->fe_fd, FE_READ_SIGNAL_STRENGTH, &signal) == -1)
|
183
|
signal = -2;
|
184
|
if (ioctl(a->fe_fd, FE_READ_SNR, &snr) == -1)
|
185
|
snr = -2;
|
186
|
if (ioctl(a->fe_fd, FE_READ_BER, &ber) == -1)
|
187
|
ber = -2;
|
188
|
if (ioctl(a->fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks) == -1)
|
189
|
uncorrected_blocks = -2;
|
190
|
|
191
|
printf ("%02x | %3u%% | %3u%% | %5d | %4d",
|
192
|
status, (signal * 100) / 0xffff, (snr * 100) / 0xffff, ber, uncorrected_blocks);
|
193
|
}
|
194
|
|
195
|
void print_status()
|
196
|
{
|
197
|
printf("%12ld | ", adapter[0].byte_counter);
|
198
|
print_frontend_status(&adapter[0]);
|
199
|
printf(" ||| ");
|
200
|
printf("%12ld | ", adapter[1].byte_counter);
|
201
|
print_frontend_status(&adapter[1]);
|
202
|
printf("\n");
|
203
|
}
|
204
|
|
205
|
void open_adapter_devices(struct adapter_struct *a)
|
206
|
{
|
207
|
a->fe_fd = open(a->fe_name, O_RDWR | O_NONBLOCK, 0);
|
208
|
a->dvr_fd = open(a->dvr_name, O_RDONLY | O_NONBLOCK, 0);
|
209
|
a->dmx_fd = open(a->dmx_name, O_RDWR, 0);
|
210
|
if (a->fe_fd < 0 || a->dvr_fd < 0 || a->dmx_fd < 0)
|
211
|
printf("Error opening adapter device.\n");
|
212
|
}
|
213
|
|
214
|
void close_adapter_devices(const struct adapter_struct *a)
|
215
|
{
|
216
|
close(a->fe_fd);
|
217
|
close(a->dvr_fd);
|
218
|
close(a->dmx_fd);
|
219
|
}
|
220
|
|
221
|
void setup_diseqc_switch(const struct adapter_struct *a, const struct channel_struct *ch)
|
222
|
{
|
223
|
int hiband = 0;
|
224
|
if (ch->freq >= SWITCHVAL) hiband = 1;
|
225
|
diseqc(a->fe_fd, ch->sat_no, ch->pol, hiband);
|
226
|
}
|
227
|
|
228
|
void tune(const struct adapter_struct *a, const struct channel_struct *ch)
|
229
|
{
|
230
|
struct dtv_property p[] = {
|
231
|
{ .cmd = DTV_CLEAR },
|
232
|
};
|
233
|
|
234
|
struct dtv_properties cmdseq = {
|
235
|
.num = 1,
|
236
|
.props = p
|
237
|
};
|
238
|
|
239
|
int hiband = 0;
|
240
|
uint32_t ifreq;
|
241
|
|
242
|
if (ch->freq >= SWITCHVAL) hiband = 1;
|
243
|
if (hiband)
|
244
|
ifreq = ch->freq - HIGHVAL;
|
245
|
else {
|
246
|
if (ch->freq < LOWVAL)
|
247
|
ifreq = LOWVAL - ch->freq;
|
248
|
else
|
249
|
ifreq = ch->freq - LOWVAL;
|
250
|
}
|
251
|
/* Tune */
|
252
|
if (ioctl(a->fe_fd, FE_SET_PROPERTY, &cmdseq) == -1)
|
253
|
perror("FE_SET_PROPERTY failed");
|
254
|
do_tune(a->fe_fd, ifreq, ch->sr, ch->delivery, ch->modulation, ch->fec, ch->rolloff);
|
255
|
}
|
256
|
|
257
|
void configure_demuxer(const struct adapter_struct *a)
|
258
|
{
|
259
|
struct dmx_pes_filter_params dmx_param;
|
260
|
|
261
|
memset(&dmx_param, 0, sizeof(dmx_param));
|
262
|
dmx_param.pid = 0x2000;
|
263
|
dmx_param.input = DMX_IN_FRONTEND;
|
264
|
dmx_param.output = DMX_OUT_TS_TAP;
|
265
|
dmx_param.pes_type = DMX_PES_OTHER;
|
266
|
dmx_param.flags = DMX_IMMEDIATE_START;
|
267
|
|
268
|
if (ioctl(a->dmx_fd, DMX_SET_PES_FILTER, &dmx_param) == -1)
|
269
|
perror("DMX_SET_PES_FILTER failed");
|
270
|
}
|
271
|
|
272
|
void test_loop_5s(void)
|
273
|
{
|
274
|
int t, last_t, c;
|
275
|
time_t start_time;
|
276
|
|
277
|
start_time = time(NULL);
|
278
|
last_t = -1;
|
279
|
|
280
|
adapter[0].byte_counter = 0;
|
281
|
adapter[1].byte_counter = 0;
|
282
|
|
283
|
while((t = (time(NULL) - start_time)) < 5) {
|
284
|
c = read(adapter[0].dvr_fd, adapter[0].buffer, BUFSIZE);
|
285
|
if (c > 0)
|
286
|
adapter[0].byte_counter += c;
|
287
|
|
288
|
c = read(adapter[1].dvr_fd, adapter[1].buffer, BUFSIZE);
|
289
|
if (c > 0)
|
290
|
adapter[1].byte_counter += c;
|
291
|
|
292
|
if (t > last_t) {
|
293
|
print_status();
|
294
|
last_t = t;
|
295
|
}
|
296
|
}
|
297
|
|
298
|
printf("adapter0: ");
|
299
|
if (adapter[0].byte_counter == 0)
|
300
|
printf("FAIL ");
|
301
|
else
|
302
|
printf("OK ");
|
303
|
printf("adapter1: ");
|
304
|
if (adapter[1].byte_counter == 0)
|
305
|
printf("FAIL ");
|
306
|
else
|
307
|
printf("OK ");
|
308
|
printf("\n");
|
309
|
}
|
310
|
|
311
|
int main()
|
312
|
{
|
313
|
int i, s;
|
314
|
|
315
|
for (i = 0; i < 6; i++) {
|
316
|
s = i % 2;
|
317
|
printf("Iteration: %d, sleep(%d)\n", i, s);
|
318
|
|
319
|
open_adapter_devices(&adapter[0]);
|
320
|
sleep(s); // Apparently sleep is required here
|
321
|
open_adapter_devices(&adapter[1]);
|
322
|
|
323
|
/* First adapter */
|
324
|
setup_diseqc_switch(&adapter[0], channel[0]);
|
325
|
tune(&adapter[0], channel[0]);
|
326
|
configure_demuxer(&adapter[0]);
|
327
|
|
328
|
/* Second adapter */
|
329
|
setup_diseqc_switch(&adapter[1], channel[1]);
|
330
|
tune(&adapter[1], channel[1]);
|
331
|
configure_demuxer(&adapter[1]);
|
332
|
|
333
|
test_loop_5s();
|
334
|
|
335
|
close_adapter_devices(&adapter[0]);
|
336
|
close_adapter_devices(&adapter[1]);
|
337
|
}
|
338
|
return 0;
|
339
|
}
|