blob: bf0a8617de9244a4794f4e37c2d217c14ebb8a38 [file] [log] [blame]
Markus Heiser5377d912016-06-30 15:18:56 +02001.. -*- coding: utf-8; mode: rst -*-
2
3.. _dvb_examples:
4
5********
6Examples
7********
8
9In this section we would like to present some examples for using the DVB
10API.
11
Mauro Carvalho Chehab706f8a92016-07-10 11:57:43 -030012..note:: This section is out of date, and the code below won't even
13 compile. Please refer to the
14 `libdvbv5 <https://linuxtv.org/docs/libdvbv5/index.html>`__ for
15 updated/recommended examples.
Markus Heiser5377d912016-06-30 15:18:56 +020016
17
18.. _tuning:
19
Mauro Carvalho Chehab282f02c2016-07-10 08:22:19 -030020Example: Tuning
21===============
Markus Heiser5377d912016-06-30 15:18:56 +020022
23We will start with a generic tuning subroutine that uses the frontend
24and SEC, as well as the demux devices. The example is given for QPSK
25tuners, but can easily be adjusted for QAM.
26
27
28.. code-block:: c
29
30 #include <sys/ioctl.h>
31 #include <stdio.h>
32 #include <stdint.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <time.h>
37 #include <unistd.h>
38
39 #include <linux/dvb/dmx.h>
40 #include <linux/dvb/frontend.h>
41 #include <linux/dvb/sec.h>
42 #include <sys/poll.h>
43
44 #define DMX "/dev/dvb/adapter0/demux1"
45 #define FRONT "/dev/dvb/adapter0/frontend1"
46 #define SEC "/dev/dvb/adapter0/sec1"
47
48 /* routine for checking if we have a signal and other status information*/
49 int FEReadStatus(int fd, fe_status_t *stat)
50 {
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -030051 int ans;
Markus Heiser5377d912016-06-30 15:18:56 +020052
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -030053 if ( (ans = ioctl(fd,FE_READ_STATUS,stat) < 0)){
54 perror("FE READ STATUS: ");
55 return -1;
56 }
Markus Heiser5377d912016-06-30 15:18:56 +020057
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -030058 if (*stat & FE_HAS_POWER)
59 printf("FE HAS POWER\\n");
Markus Heiser5377d912016-06-30 15:18:56 +020060
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -030061 if (*stat & FE_HAS_SIGNAL)
62 printf("FE HAS SIGNAL\\n");
Markus Heiser5377d912016-06-30 15:18:56 +020063
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -030064 if (*stat & FE_SPECTRUM_INV)
65 printf("SPEKTRUM INV\\n");
Markus Heiser5377d912016-06-30 15:18:56 +020066
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -030067 return 0;
Markus Heiser5377d912016-06-30 15:18:56 +020068 }
69
70
71 /* tune qpsk */
72 /* freq: frequency of transponder */
73 /* vpid, apid, tpid: PIDs of video, audio and teletext TS packets */
74 /* diseqc: DiSEqC address of the used LNB */
75 /* pol: Polarisation */
76 /* srate: Symbol Rate */
77 /* fec. FEC */
78 /* lnb_lof1: local frequency of lower LNB band */
79 /* lnb_lof2: local frequency of upper LNB band */
80 /* lnb_slof: switch frequency of LNB */
81
82 int set_qpsk_channel(int freq, int vpid, int apid, int tpid,
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -030083 int diseqc, int pol, int srate, int fec, int lnb_lof1,
84 int lnb_lof2, int lnb_slof)
Markus Heiser5377d912016-06-30 15:18:56 +020085 {
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -030086 struct secCommand scmd;
87 struct secCmdSequence scmds;
88 struct dmx_pes_filter_params pesFilterParams;
89 FrontendParameters frp;
90 struct pollfd pfd[1];
91 FrontendEvent event;
92 int demux1, demux2, demux3, front;
Markus Heiser5377d912016-06-30 15:18:56 +020093
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -030094 frequency = (uint32_t) freq;
95 symbolrate = (uint32_t) srate;
Markus Heiser5377d912016-06-30 15:18:56 +020096
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -030097 if((front = open(FRONT,O_RDWR)) < 0){
98 perror("FRONTEND DEVICE: ");
99 return -1;
100 }
Markus Heiser5377d912016-06-30 15:18:56 +0200101
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300102 if((sec = open(SEC,O_RDWR)) < 0){
103 perror("SEC DEVICE: ");
104 return -1;
105 }
Markus Heiser5377d912016-06-30 15:18:56 +0200106
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300107 if (demux1 < 0){
108 if ((demux1=open(DMX, O_RDWR|O_NONBLOCK))
109 < 0){
110 perror("DEMUX DEVICE: ");
111 return -1;
112 }
113 }
Markus Heiser5377d912016-06-30 15:18:56 +0200114
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300115 if (demux2 < 0){
116 if ((demux2=open(DMX, O_RDWR|O_NONBLOCK))
117 < 0){
118 perror("DEMUX DEVICE: ");
119 return -1;
120 }
121 }
Markus Heiser5377d912016-06-30 15:18:56 +0200122
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300123 if (demux3 < 0){
124 if ((demux3=open(DMX, O_RDWR|O_NONBLOCK))
125 < 0){
126 perror("DEMUX DEVICE: ");
127 return -1;
128 }
129 }
Markus Heiser5377d912016-06-30 15:18:56 +0200130
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300131 if (freq < lnb_slof) {
132 frp.Frequency = (freq - lnb_lof1);
133 scmds.continuousTone = SEC_TONE_OFF;
134 } else {
135 frp.Frequency = (freq - lnb_lof2);
136 scmds.continuousTone = SEC_TONE_ON;
137 }
138 frp.Inversion = INVERSION_AUTO;
139 if (pol) scmds.voltage = SEC_VOLTAGE_18;
140 else scmds.voltage = SEC_VOLTAGE_13;
Markus Heiser5377d912016-06-30 15:18:56 +0200141
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300142 scmd.type=0;
143 scmd.u.diseqc.addr=0x10;
144 scmd.u.diseqc.cmd=0x38;
145 scmd.u.diseqc.numParams=1;
146 scmd.u.diseqc.params[0] = 0xF0 | ((diseqc * 4) & 0x0F) |
147 (scmds.continuousTone == SEC_TONE_ON ? 1 : 0) |
148 (scmds.voltage==SEC_VOLTAGE_18 ? 2 : 0);
Markus Heiser5377d912016-06-30 15:18:56 +0200149
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300150 scmds.miniCommand=SEC_MINI_NONE;
151 scmds.numCommands=1;
152 scmds.commands=&scmd;
153 if (ioctl(sec, SEC_SEND_SEQUENCE, &scmds) < 0){
154 perror("SEC SEND: ");
155 return -1;
156 }
Markus Heiser5377d912016-06-30 15:18:56 +0200157
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300158 if (ioctl(sec, SEC_SEND_SEQUENCE, &scmds) < 0){
159 perror("SEC SEND: ");
160 return -1;
161 }
Markus Heiser5377d912016-06-30 15:18:56 +0200162
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300163 frp.u.qpsk.SymbolRate = srate;
164 frp.u.qpsk.FEC_inner = fec;
Markus Heiser5377d912016-06-30 15:18:56 +0200165
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300166 if (ioctl(front, FE_SET_FRONTEND, &frp) < 0){
167 perror("QPSK TUNE: ");
168 return -1;
169 }
Markus Heiser5377d912016-06-30 15:18:56 +0200170
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300171 pfd[0].fd = front;
172 pfd[0].events = POLLIN;
Markus Heiser5377d912016-06-30 15:18:56 +0200173
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300174 if (poll(pfd,1,3000)){
175 if (pfd[0].revents & POLLIN){
176 printf("Getting QPSK event\\n");
177 if ( ioctl(front, FE_GET_EVENT, &event)
Markus Heiser5377d912016-06-30 15:18:56 +0200178
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300179 == -EOVERFLOW){
180 perror("qpsk get event");
181 return -1;
182 }
183 printf("Received ");
184 switch(event.type){
185 case FE_UNEXPECTED_EV:
186 printf("unexpected event\\n");
187 return -1;
188 case FE_FAILURE_EV:
189 printf("failure event\\n");
190 return -1;
Markus Heiser5377d912016-06-30 15:18:56 +0200191
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300192 case FE_COMPLETION_EV:
193 printf("completion event\\n");
194 }
195 }
196 }
Markus Heiser5377d912016-06-30 15:18:56 +0200197
198
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300199 pesFilterParams.pid = vpid;
200 pesFilterParams.input = DMX_IN_FRONTEND;
201 pesFilterParams.output = DMX_OUT_DECODER;
202 pesFilterParams.pes_type = DMX_PES_VIDEO;
203 pesFilterParams.flags = DMX_IMMEDIATE_START;
204 if (ioctl(demux1, DMX_SET_PES_FILTER, &pesFilterParams) < 0){
205 perror("set_vpid");
206 return -1;
207 }
Markus Heiser5377d912016-06-30 15:18:56 +0200208
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300209 pesFilterParams.pid = apid;
210 pesFilterParams.input = DMX_IN_FRONTEND;
211 pesFilterParams.output = DMX_OUT_DECODER;
212 pesFilterParams.pes_type = DMX_PES_AUDIO;
213 pesFilterParams.flags = DMX_IMMEDIATE_START;
214 if (ioctl(demux2, DMX_SET_PES_FILTER, &pesFilterParams) < 0){
215 perror("set_apid");
216 return -1;
217 }
Markus Heiser5377d912016-06-30 15:18:56 +0200218
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300219 pesFilterParams.pid = tpid;
220 pesFilterParams.input = DMX_IN_FRONTEND;
221 pesFilterParams.output = DMX_OUT_DECODER;
222 pesFilterParams.pes_type = DMX_PES_TELETEXT;
223 pesFilterParams.flags = DMX_IMMEDIATE_START;
224 if (ioctl(demux3, DMX_SET_PES_FILTER, &pesFilterParams) < 0){
225 perror("set_tpid");
226 return -1;
227 }
Markus Heiser5377d912016-06-30 15:18:56 +0200228
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300229 return has_signal(fds);
Markus Heiser5377d912016-06-30 15:18:56 +0200230 }
231
232The program assumes that you are using a universal LNB and a standard
233DiSEqC switch with up to 4 addresses. Of course, you could build in some
234more checking if tuning was successful and maybe try to repeat the
235tuning process. Depending on the external hardware, i.e. LNB and DiSEqC
236switch, and weather conditions this may be necessary.
237
238
239.. _the_dvr_device:
240
Mauro Carvalho Chehab282f02c2016-07-10 08:22:19 -0300241Example: The DVR device
242========================
Markus Heiser5377d912016-06-30 15:18:56 +0200243
244The following program code shows how to use the DVR device for
245recording.
246
247
248.. code-block:: c
249
250 #include <sys/ioctl.h>
251 #include <stdio.h>
252 #include <stdint.h>
253 #include <sys/types.h>
254 #include <sys/stat.h>
255 #include <fcntl.h>
256 #include <time.h>
257 #include <unistd.h>
258
259 #include <linux/dvb/dmx.h>
260 #include <linux/dvb/video.h>
261 #include <sys/poll.h>
262 #define DVR "/dev/dvb/adapter0/dvr1"
263 #define AUDIO "/dev/dvb/adapter0/audio1"
264 #define VIDEO "/dev/dvb/adapter0/video1"
265
266 #define BUFFY (188*20)
267 #define MAX_LENGTH (1024*1024*5) /* record 5MB */
268
269
270 /* switch the demuxes to recording, assuming the transponder is tuned */
271
272 /* demux1, demux2: file descriptor of video and audio filters */
273 /* vpid, apid: PIDs of video and audio channels */
274
275 int switch_to_record(int demux1, int demux2, uint16_t vpid, uint16_t apid)
276 {
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300277 struct dmx_pes_filter_params pesFilterParams;
Markus Heiser5377d912016-06-30 15:18:56 +0200278
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300279 if (demux1 < 0){
280 if ((demux1=open(DMX, O_RDWR|O_NONBLOCK))
281 < 0){
282 perror("DEMUX DEVICE: ");
283 return -1;
284 }
285 }
Markus Heiser5377d912016-06-30 15:18:56 +0200286
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300287 if (demux2 < 0){
288 if ((demux2=open(DMX, O_RDWR|O_NONBLOCK))
289 < 0){
290 perror("DEMUX DEVICE: ");
291 return -1;
292 }
293 }
Markus Heiser5377d912016-06-30 15:18:56 +0200294
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300295 pesFilterParams.pid = vpid;
296 pesFilterParams.input = DMX_IN_FRONTEND;
297 pesFilterParams.output = DMX_OUT_TS_TAP;
298 pesFilterParams.pes_type = DMX_PES_VIDEO;
299 pesFilterParams.flags = DMX_IMMEDIATE_START;
300 if (ioctl(demux1, DMX_SET_PES_FILTER, &pesFilterParams) < 0){
301 perror("DEMUX DEVICE");
302 return -1;
303 }
304 pesFilterParams.pid = apid;
305 pesFilterParams.input = DMX_IN_FRONTEND;
306 pesFilterParams.output = DMX_OUT_TS_TAP;
307 pesFilterParams.pes_type = DMX_PES_AUDIO;
308 pesFilterParams.flags = DMX_IMMEDIATE_START;
309 if (ioctl(demux2, DMX_SET_PES_FILTER, &pesFilterParams) < 0){
310 perror("DEMUX DEVICE");
311 return -1;
312 }
313 return 0;
Markus Heiser5377d912016-06-30 15:18:56 +0200314 }
315
316 /* start recording MAX_LENGTH , assuming the transponder is tuned */
317
318 /* demux1, demux2: file descriptor of video and audio filters */
319 /* vpid, apid: PIDs of video and audio channels */
320 int record_dvr(int demux1, int demux2, uint16_t vpid, uint16_t apid)
321 {
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300322 int i;
323 int len;
324 int written;
325 uint8_t buf[BUFFY];
326 uint64_t length;
327 struct pollfd pfd[1];
328 int dvr, dvr_out;
Markus Heiser5377d912016-06-30 15:18:56 +0200329
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300330 /* open dvr device */
331 if ((dvr = open(DVR, O_RDONLY|O_NONBLOCK)) < 0){
332 perror("DVR DEVICE");
333 return -1;
334 }
Markus Heiser5377d912016-06-30 15:18:56 +0200335
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300336 /* switch video and audio demuxes to dvr */
337 printf ("Switching dvr on\\n");
338 i = switch_to_record(demux1, demux2, vpid, apid);
339 printf("finished: ");
Markus Heiser5377d912016-06-30 15:18:56 +0200340
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300341 printf("Recording %2.0f MB of test file in TS format\\n",
342 MAX_LENGTH/(1024.0*1024.0));
343 length = 0;
Markus Heiser5377d912016-06-30 15:18:56 +0200344
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300345 /* open output file */
346 if ((dvr_out = open(DVR_FILE,O_WRONLY|O_CREAT
347 |O_TRUNC, S_IRUSR|S_IWUSR
348 |S_IRGRP|S_IWGRP|S_IROTH|
349 S_IWOTH)) < 0){
350 perror("Can't open file for dvr test");
351 return -1;
352 }
Markus Heiser5377d912016-06-30 15:18:56 +0200353
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300354 pfd[0].fd = dvr;
355 pfd[0].events = POLLIN;
Markus Heiser5377d912016-06-30 15:18:56 +0200356
Mauro Carvalho Chehab0579e6e2016-07-04 16:25:48 -0300357 /* poll for dvr data and write to file */
358 while (length < MAX_LENGTH ) {
359 if (poll(pfd,1,1)){
360 if (pfd[0].revents & POLLIN){
361 len = read(dvr, buf, BUFFY);
362 if (len < 0){
363 perror("recording");
364 return -1;
365 }
366 if (len > 0){
367 written = 0;
368 while (written < len)
369 written +=
370 write (dvr_out,
371 buf, len);
372 length += len;
373 printf("written %2.0f MB\\r",
374 length/1024./1024.);
375 }
376 }
377 }
378 }
379 return 0;
Markus Heiser5377d912016-06-30 15:18:56 +0200380 }