Commit | Line | Data |
---|---|---|
5377d91f MH |
1 | .. -*- coding: utf-8; mode: rst -*- |
2 | ||
3 | .. _dvb_examples: | |
4 | ||
5 | ******** | |
6 | Examples | |
7 | ******** | |
8 | ||
9 | In this section we would like to present some examples for using the DVB | |
10 | API. | |
11 | ||
8d4b231a | 12 | .. note:: |
b6b6e678 MCC |
13 | |
14 | This section is out of date, and the code below won't even | |
706f8a99 MCC |
15 | compile. Please refer to the |
16 | `libdvbv5 <https://linuxtv.org/docs/libdvbv5/index.html>`__ for | |
17 | updated/recommended examples. | |
5377d91f MH |
18 | |
19 | ||
20 | .. _tuning: | |
21 | ||
282f02cb MCC |
22 | Example: Tuning |
23 | =============== | |
5377d91f MH |
24 | |
25 | We will start with a generic tuning subroutine that uses the frontend | |
26 | and SEC, as well as the demux devices. The example is given for QPSK | |
27 | tuners, but can easily be adjusted for QAM. | |
28 | ||
29 | ||
30 | .. code-block:: c | |
31 | ||
32 | #include <sys/ioctl.h> | |
33 | #include <stdio.h> | |
34 | #include <stdint.h> | |
35 | #include <sys/types.h> | |
36 | #include <sys/stat.h> | |
37 | #include <fcntl.h> | |
38 | #include <time.h> | |
39 | #include <unistd.h> | |
40 | ||
41 | #include <linux/dvb/dmx.h> | |
42 | #include <linux/dvb/frontend.h> | |
43 | #include <linux/dvb/sec.h> | |
44 | #include <sys/poll.h> | |
45 | ||
46 | #define DMX "/dev/dvb/adapter0/demux1" | |
47 | #define FRONT "/dev/dvb/adapter0/frontend1" | |
48 | #define SEC "/dev/dvb/adapter0/sec1" | |
49 | ||
50 | /* routine for checking if we have a signal and other status information*/ | |
51 | int FEReadStatus(int fd, fe_status_t *stat) | |
52 | { | |
0579e6e3 | 53 | int ans; |
5377d91f | 54 | |
0579e6e3 MCC |
55 | if ( (ans = ioctl(fd,FE_READ_STATUS,stat) < 0)){ |
56 | perror("FE READ STATUS: "); | |
57 | return -1; | |
58 | } | |
5377d91f | 59 | |
0579e6e3 MCC |
60 | if (*stat & FE_HAS_POWER) |
61 | printf("FE HAS POWER\\n"); | |
5377d91f | 62 | |
0579e6e3 MCC |
63 | if (*stat & FE_HAS_SIGNAL) |
64 | printf("FE HAS SIGNAL\\n"); | |
5377d91f | 65 | |
0579e6e3 MCC |
66 | if (*stat & FE_SPECTRUM_INV) |
67 | printf("SPEKTRUM INV\\n"); | |
5377d91f | 68 | |
0579e6e3 | 69 | return 0; |
5377d91f MH |
70 | } |
71 | ||
72 | ||
73 | /* tune qpsk */ | |
74 | /* freq: frequency of transponder */ | |
75 | /* vpid, apid, tpid: PIDs of video, audio and teletext TS packets */ | |
76 | /* diseqc: DiSEqC address of the used LNB */ | |
77 | /* pol: Polarisation */ | |
78 | /* srate: Symbol Rate */ | |
79 | /* fec. FEC */ | |
80 | /* lnb_lof1: local frequency of lower LNB band */ | |
81 | /* lnb_lof2: local frequency of upper LNB band */ | |
82 | /* lnb_slof: switch frequency of LNB */ | |
83 | ||
84 | int set_qpsk_channel(int freq, int vpid, int apid, int tpid, | |
0579e6e3 MCC |
85 | int diseqc, int pol, int srate, int fec, int lnb_lof1, |
86 | int lnb_lof2, int lnb_slof) | |
5377d91f | 87 | { |
0579e6e3 MCC |
88 | struct secCommand scmd; |
89 | struct secCmdSequence scmds; | |
90 | struct dmx_pes_filter_params pesFilterParams; | |
91 | FrontendParameters frp; | |
8968da9b | 92 | struct pollfd pfd[1]; |
0579e6e3 MCC |
93 | FrontendEvent event; |
94 | int demux1, demux2, demux3, front; | |
95 | ||
96 | frequency = (uint32_t) freq; | |
97 | symbolrate = (uint32_t) srate; | |
98 | ||
99 | if((front = open(FRONT,O_RDWR)) < 0){ | |
100 | perror("FRONTEND DEVICE: "); | |
101 | return -1; | |
102 | } | |
103 | ||
104 | if((sec = open(SEC,O_RDWR)) < 0){ | |
105 | perror("SEC DEVICE: "); | |
106 | return -1; | |
107 | } | |
108 | ||
109 | if (demux1 < 0){ | |
110 | if ((demux1=open(DMX, O_RDWR|O_NONBLOCK)) | |
111 | < 0){ | |
112 | perror("DEMUX DEVICE: "); | |
113 | return -1; | |
114 | } | |
115 | } | |
116 | ||
117 | if (demux2 < 0){ | |
118 | if ((demux2=open(DMX, O_RDWR|O_NONBLOCK)) | |
119 | < 0){ | |
120 | perror("DEMUX DEVICE: "); | |
121 | return -1; | |
122 | } | |
123 | } | |
124 | ||
125 | if (demux3 < 0){ | |
126 | if ((demux3=open(DMX, O_RDWR|O_NONBLOCK)) | |
127 | < 0){ | |
128 | perror("DEMUX DEVICE: "); | |
129 | return -1; | |
130 | } | |
131 | } | |
132 | ||
133 | if (freq < lnb_slof) { | |
134 | frp.Frequency = (freq - lnb_lof1); | |
135 | scmds.continuousTone = SEC_TONE_OFF; | |
136 | } else { | |
137 | frp.Frequency = (freq - lnb_lof2); | |
138 | scmds.continuousTone = SEC_TONE_ON; | |
139 | } | |
140 | frp.Inversion = INVERSION_AUTO; | |
141 | if (pol) scmds.voltage = SEC_VOLTAGE_18; | |
142 | else scmds.voltage = SEC_VOLTAGE_13; | |
143 | ||
144 | scmd.type=0; | |
145 | scmd.u.diseqc.addr=0x10; | |
146 | scmd.u.diseqc.cmd=0x38; | |
147 | scmd.u.diseqc.numParams=1; | |
8968da9b | 148 | scmd.u.diseqc.params[0] = 0xF0 | ((diseqc * 4) & 0x0F) | |
0579e6e3 MCC |
149 | (scmds.continuousTone == SEC_TONE_ON ? 1 : 0) | |
150 | (scmds.voltage==SEC_VOLTAGE_18 ? 2 : 0); | |
151 | ||
152 | scmds.miniCommand=SEC_MINI_NONE; | |
153 | scmds.numCommands=1; | |
154 | scmds.commands=&scmd; | |
155 | if (ioctl(sec, SEC_SEND_SEQUENCE, &scmds) < 0){ | |
156 | perror("SEC SEND: "); | |
157 | return -1; | |
158 | } | |
159 | ||
160 | if (ioctl(sec, SEC_SEND_SEQUENCE, &scmds) < 0){ | |
161 | perror("SEC SEND: "); | |
162 | return -1; | |
163 | } | |
164 | ||
165 | frp.u.qpsk.SymbolRate = srate; | |
166 | frp.u.qpsk.FEC_inner = fec; | |
167 | ||
168 | if (ioctl(front, FE_SET_FRONTEND, &frp) < 0){ | |
169 | perror("QPSK TUNE: "); | |
170 | return -1; | |
171 | } | |
172 | ||
8968da9b MCC |
173 | pfd[0].fd = front; |
174 | pfd[0].events = POLLIN; | |
0579e6e3 MCC |
175 | |
176 | if (poll(pfd,1,3000)){ | |
8968da9b | 177 | if (pfd[0].revents & POLLIN){ |
0579e6e3 MCC |
178 | printf("Getting QPSK event\\n"); |
179 | if ( ioctl(front, FE_GET_EVENT, &event) | |
180 | ||
181 | == -EOVERFLOW){ | |
182 | perror("qpsk get event"); | |
183 | return -1; | |
184 | } | |
185 | printf("Received "); | |
186 | switch(event.type){ | |
187 | case FE_UNEXPECTED_EV: | |
188 | printf("unexpected event\\n"); | |
189 | return -1; | |
190 | case FE_FAILURE_EV: | |
191 | printf("failure event\\n"); | |
192 | return -1; | |
193 | ||
194 | case FE_COMPLETION_EV: | |
195 | printf("completion event\\n"); | |
196 | } | |
197 | } | |
198 | } | |
199 | ||
200 | ||
201 | pesFilterParams.pid = vpid; | |
202 | pesFilterParams.input = DMX_IN_FRONTEND; | |
203 | pesFilterParams.output = DMX_OUT_DECODER; | |
204 | pesFilterParams.pes_type = DMX_PES_VIDEO; | |
205 | pesFilterParams.flags = DMX_IMMEDIATE_START; | |
206 | if (ioctl(demux1, DMX_SET_PES_FILTER, &pesFilterParams) < 0){ | |
207 | perror("set_vpid"); | |
208 | return -1; | |
209 | } | |
210 | ||
211 | pesFilterParams.pid = apid; | |
212 | pesFilterParams.input = DMX_IN_FRONTEND; | |
213 | pesFilterParams.output = DMX_OUT_DECODER; | |
214 | pesFilterParams.pes_type = DMX_PES_AUDIO; | |
215 | pesFilterParams.flags = DMX_IMMEDIATE_START; | |
216 | if (ioctl(demux2, DMX_SET_PES_FILTER, &pesFilterParams) < 0){ | |
217 | perror("set_apid"); | |
218 | return -1; | |
219 | } | |
220 | ||
221 | pesFilterParams.pid = tpid; | |
222 | pesFilterParams.input = DMX_IN_FRONTEND; | |
223 | pesFilterParams.output = DMX_OUT_DECODER; | |
224 | pesFilterParams.pes_type = DMX_PES_TELETEXT; | |
225 | pesFilterParams.flags = DMX_IMMEDIATE_START; | |
226 | if (ioctl(demux3, DMX_SET_PES_FILTER, &pesFilterParams) < 0){ | |
227 | perror("set_tpid"); | |
228 | return -1; | |
229 | } | |
230 | ||
231 | return has_signal(fds); | |
5377d91f MH |
232 | } |
233 | ||
234 | The program assumes that you are using a universal LNB and a standard | |
235 | DiSEqC switch with up to 4 addresses. Of course, you could build in some | |
236 | more checking if tuning was successful and maybe try to repeat the | |
237 | tuning process. Depending on the external hardware, i.e. LNB and DiSEqC | |
238 | switch, and weather conditions this may be necessary. | |
239 | ||
240 | ||
241 | .. _the_dvr_device: | |
242 | ||
282f02cb MCC |
243 | Example: The DVR device |
244 | ======================== | |
5377d91f MH |
245 | |
246 | The following program code shows how to use the DVR device for | |
247 | recording. | |
248 | ||
249 | ||
250 | .. code-block:: c | |
251 | ||
252 | #include <sys/ioctl.h> | |
253 | #include <stdio.h> | |
254 | #include <stdint.h> | |
255 | #include <sys/types.h> | |
256 | #include <sys/stat.h> | |
257 | #include <fcntl.h> | |
258 | #include <time.h> | |
259 | #include <unistd.h> | |
260 | ||
261 | #include <linux/dvb/dmx.h> | |
262 | #include <linux/dvb/video.h> | |
263 | #include <sys/poll.h> | |
264 | #define DVR "/dev/dvb/adapter0/dvr1" | |
265 | #define AUDIO "/dev/dvb/adapter0/audio1" | |
266 | #define VIDEO "/dev/dvb/adapter0/video1" | |
267 | ||
268 | #define BUFFY (188*20) | |
269 | #define MAX_LENGTH (1024*1024*5) /* record 5MB */ | |
270 | ||
271 | ||
272 | /* switch the demuxes to recording, assuming the transponder is tuned */ | |
273 | ||
274 | /* demux1, demux2: file descriptor of video and audio filters */ | |
275 | /* vpid, apid: PIDs of video and audio channels */ | |
276 | ||
277 | int switch_to_record(int demux1, int demux2, uint16_t vpid, uint16_t apid) | |
278 | { | |
0579e6e3 MCC |
279 | struct dmx_pes_filter_params pesFilterParams; |
280 | ||
281 | if (demux1 < 0){ | |
282 | if ((demux1=open(DMX, O_RDWR|O_NONBLOCK)) | |
283 | < 0){ | |
284 | perror("DEMUX DEVICE: "); | |
285 | return -1; | |
286 | } | |
287 | } | |
288 | ||
289 | if (demux2 < 0){ | |
290 | if ((demux2=open(DMX, O_RDWR|O_NONBLOCK)) | |
291 | < 0){ | |
292 | perror("DEMUX DEVICE: "); | |
293 | return -1; | |
294 | } | |
295 | } | |
296 | ||
297 | pesFilterParams.pid = vpid; | |
298 | pesFilterParams.input = DMX_IN_FRONTEND; | |
299 | pesFilterParams.output = DMX_OUT_TS_TAP; | |
300 | pesFilterParams.pes_type = DMX_PES_VIDEO; | |
301 | pesFilterParams.flags = DMX_IMMEDIATE_START; | |
302 | if (ioctl(demux1, DMX_SET_PES_FILTER, &pesFilterParams) < 0){ | |
303 | perror("DEMUX DEVICE"); | |
304 | return -1; | |
305 | } | |
306 | pesFilterParams.pid = apid; | |
307 | pesFilterParams.input = DMX_IN_FRONTEND; | |
308 | pesFilterParams.output = DMX_OUT_TS_TAP; | |
309 | pesFilterParams.pes_type = DMX_PES_AUDIO; | |
310 | pesFilterParams.flags = DMX_IMMEDIATE_START; | |
311 | if (ioctl(demux2, DMX_SET_PES_FILTER, &pesFilterParams) < 0){ | |
312 | perror("DEMUX DEVICE"); | |
313 | return -1; | |
314 | } | |
315 | return 0; | |
5377d91f MH |
316 | } |
317 | ||
318 | /* start recording MAX_LENGTH , assuming the transponder is tuned */ | |
319 | ||
320 | /* demux1, demux2: file descriptor of video and audio filters */ | |
321 | /* vpid, apid: PIDs of video and audio channels */ | |
322 | int record_dvr(int demux1, int demux2, uint16_t vpid, uint16_t apid) | |
323 | { | |
0579e6e3 MCC |
324 | int i; |
325 | int len; | |
326 | int written; | |
327 | uint8_t buf[BUFFY]; | |
328 | uint64_t length; | |
8968da9b | 329 | struct pollfd pfd[1]; |
0579e6e3 MCC |
330 | int dvr, dvr_out; |
331 | ||
332 | /* open dvr device */ | |
333 | if ((dvr = open(DVR, O_RDONLY|O_NONBLOCK)) < 0){ | |
334 | perror("DVR DEVICE"); | |
335 | return -1; | |
336 | } | |
337 | ||
338 | /* switch video and audio demuxes to dvr */ | |
339 | printf ("Switching dvr on\\n"); | |
340 | i = switch_to_record(demux1, demux2, vpid, apid); | |
341 | printf("finished: "); | |
342 | ||
343 | printf("Recording %2.0f MB of test file in TS format\\n", | |
344 | MAX_LENGTH/(1024.0*1024.0)); | |
345 | length = 0; | |
346 | ||
347 | /* open output file */ | |
348 | if ((dvr_out = open(DVR_FILE,O_WRONLY|O_CREAT | |
349 | |O_TRUNC, S_IRUSR|S_IWUSR | |
350 | |S_IRGRP|S_IWGRP|S_IROTH| | |
351 | S_IWOTH)) < 0){ | |
352 | perror("Can't open file for dvr test"); | |
353 | return -1; | |
354 | } | |
355 | ||
8968da9b MCC |
356 | pfd[0].fd = dvr; |
357 | pfd[0].events = POLLIN; | |
0579e6e3 MCC |
358 | |
359 | /* poll for dvr data and write to file */ | |
360 | while (length < MAX_LENGTH ) { | |
361 | if (poll(pfd,1,1)){ | |
8968da9b | 362 | if (pfd[0].revents & POLLIN){ |
0579e6e3 MCC |
363 | len = read(dvr, buf, BUFFY); |
364 | if (len < 0){ | |
365 | perror("recording"); | |
366 | return -1; | |
367 | } | |
368 | if (len > 0){ | |
369 | written = 0; | |
370 | while (written < len) | |
371 | written += | |
372 | write (dvr_out, | |
373 | buf, len); | |
374 | length += len; | |
375 | printf("written %2.0f MB\\r", | |
376 | length/1024./1024.); | |
377 | } | |
378 | } | |
379 | } | |
380 | } | |
381 | return 0; | |
5377d91f | 382 | } |