removed some tabs
[senf.git] / Socket / Protocols / DVB / DVBSocketController.cc
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Anton Gillert <atx@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23
24 #include "senf/Utils/Exception.hh"
25 #include "senf/Utils/Logger/Logger.hh"
26 #include "senf/Utils/membind.hh"
27
28 #include "DVBSocketController.hh"
29 #include <sstream>
30 using namespace std;
31 #define prefix_
32
33
34
35 senf::DVBSocketController::DVBSocketController(DVBFrontendHandle frontendHandle_, DVBDemuxSectionHandle sectionHandle_ , const Callback & cb_) :
36     dir( this ),
37     frontendHandle( frontendHandle_ ),
38     sectionHandle( sectionHandle_ ),
39     type( frontendHandle.protocol().getInfo().type ),
40     parser( type ),
41     cb( cb_ ),
42     event( "senf::DVBSocketController::readEvent", senf::membind(&DVBSocketController::readEvent, this), frontendHandle, senf::scheduler::FdEvent::EV_PRIO, false )
43 {
44     initConsole();
45 }
46
47 prefix_ senf::DVBSocketController::~DVBSocketController()
48 {
49 }
50 prefix_ void senf::DVBSocketController::tuneToCMD(const string & input, const string & mode){
51     struct dvb_frontend_parameters frontend;
52     
53   
54     // no valid configline, so it will be treaten like a channel name
55     if (input.find(":")==string::npos){
56         if (mode.c_str()[0]=='a')
57             tuneTo(input);
58         else
59             tuneTo_sync(input);
60         return;
61     }
62     // add psydo name "foo" to complete configline syntax
63     frontend = parser.getFrontendParam("foo:"+input);
64     
65     if (mode.c_str()[0]=='a'){
66         switch (type) {
67             case FE_QPSK:
68                 tuneDVB_S(frontend.frequency, frontend.inversion, frontend.u.qpsk.symbol_rate, frontend.u.qpsk.fec_inner);
69                 break;
70             case FE_QAM:
71                 tuneDVB_C(frontend.frequency, frontend.inversion, frontend.u.qam.symbol_rate, frontend.u.qam.fec_inner, frontend.u.qam.modulation);
72                 break;
73             case FE_OFDM:
74                 tuneDVB_T(frontend.frequency, frontend.inversion, frontend.u.ofdm.bandwidth, frontend.u.ofdm.code_rate_HP, frontend.u.ofdm.code_rate_LP, frontend.u.ofdm.constellation, frontend.u.ofdm.transmission_mode, frontend.u.ofdm.guard_interval, frontend.u.ofdm.hierarchy_information);
75                 break;
76             default:
77                 SENF_THROW_SYSTEM_EXCEPTION("Could not determine type of card.");
78         }
79     }
80     else {
81         switch (type) {
82             case FE_QPSK:
83                 tuneDVB_S_sync(frontend.frequency, frontend.inversion, frontend.u.qpsk.symbol_rate, frontend.u.qpsk.fec_inner);
84                 break;
85             case FE_QAM:
86                 tuneDVB_C_sync(frontend.frequency, frontend.inversion, frontend.u.qam.symbol_rate, frontend.u.qam.fec_inner, frontend.u.qam.modulation);
87                 break;
88             case FE_OFDM:
89                 tuneDVB_T_sync(frontend.frequency, frontend.inversion, frontend.u.ofdm.bandwidth, frontend.u.ofdm.code_rate_HP, frontend.u.ofdm.code_rate_LP, frontend.u.ofdm.constellation, frontend.u.ofdm.transmission_mode, frontend.u.ofdm.guard_interval, frontend.u.ofdm.hierarchy_information);
90                 break;
91             default:
92                 SENF_THROW_SYSTEM_EXCEPTION("Could not determine type of card.");
93         }
94     }
95 }
96
97 prefix_ void senf::DVBSocketController::tuneTo(const string & channel)
98 {
99     struct dvb_frontend_parameters frontend;
100    
101     string configLine = parser.getConfigLine(channel);
102     
103     frontend = parser.getFrontendParam(configLine);
104     switch (type) {
105         case FE_QPSK:
106             tuneDVB_S(frontend.frequency, frontend.inversion, frontend.u.qpsk.symbol_rate, frontend.u.qpsk.fec_inner);
107             break;
108         case FE_QAM:
109             tuneDVB_C(frontend.frequency, frontend.inversion, frontend.u.qam.symbol_rate, frontend.u.qam.fec_inner, frontend.u.qam.modulation);
110             break;
111         case FE_OFDM:
112             tuneDVB_T(frontend.frequency, frontend.inversion, frontend.u.ofdm.bandwidth, frontend.u.ofdm.code_rate_HP, frontend.u.ofdm.code_rate_LP, frontend.u.ofdm.constellation, frontend.u.ofdm.transmission_mode, frontend.u.ofdm.guard_interval, frontend.u.ofdm.hierarchy_information);
113             break;
114         default:
115             SENF_THROW_SYSTEM_EXCEPTION("Could not determine type of card.");
116     }    
117 }
118
119 prefix_ void senf::DVBSocketController::tuneDVB_T(unsigned int frequency, 
120                 fe_spectral_inversion_t inversion,
121                 fe_bandwidth_t bandwidth, 
122                 fe_code_rate_t code_rate_HP, /* high priority stream code rate */
123                 fe_code_rate_t code_rate_LP, /* low priority stream code rate */
124                 fe_modulation_t constellation, /* modulation type (see above) */
125                 fe_transmit_mode_t transmission_mode, 
126                 fe_guard_interval_t guard_interval,
127                 fe_hierarchy_t hierarchy_information
128                 )
129 {
130     if(type != FE_OFDM)
131         SENF_THROW_SYSTEM_EXCEPTION("Type of card is: ") << getTypeString() << " for this operation you need a DVB-T Card!";
132     
133     event.enable();
134     
135     frontendHandle.protocol().setNonBlock();
136     frontendHandle.protocol().tuneDVB_T(frequency, 
137                 inversion, 
138                 bandwidth, 
139                 code_rate_HP, 
140                 code_rate_LP, 
141                 constellation, 
142                 transmission_mode, 
143                 guard_interval, 
144                 hierarchy_information);
145 }
146
147 prefix_ void senf::DVBSocketController::tuneDVB_S(unsigned int frequency, fe_spectral_inversion_t inversion, unsigned int symbole_rate, fe_code_rate_t code_rate){
148     if(type != FE_QPSK)
149         SENF_THROW_SYSTEM_EXCEPTION("Type of card is: ") << getTypeString() << " for this operation you need a DVB-S Card!";
150     
151     event.enable();
152     
153     frontendHandle.protocol().setNonBlock();
154     frontendHandle.protocol().tuneDVB_S(frequency, inversion, symbole_rate, code_rate);
155 }
156
157 prefix_ void senf::DVBSocketController::tuneDVB_C(unsigned int frequency, 
158                 fe_spectral_inversion_t inversion,
159                 unsigned int symbol_rate,
160                 fe_code_rate_t fec_inner,
161                 fe_modulation_t modulation
162                 )
163 {   
164     if(type != FE_QAM)
165         SENF_THROW_SYSTEM_EXCEPTION("Type of card is: ") << getTypeString() << " for this operation you need a DVB-C Card!";
166     
167     event.enable();
168     
169     frontendHandle.protocol().setNonBlock();
170     
171     frontendHandle.protocol().tuneDVB_C(frequency, inversion, symbol_rate, fec_inner, modulation);
172 }
173
174 prefix_ dvb_frontend_event senf::DVBSocketController::tuneTo_sync(const string & channel)
175 {
176     struct dvb_frontend_parameters frontend;
177     dvb_frontend_event ev;
178     string configLine = parser.getConfigLine(channel);
179     
180     frontend = parser.getFrontendParam(configLine);
181     switch (type) {
182         case FE_QPSK:
183             ev = tuneDVB_S_sync(frontend.frequency, frontend.inversion, frontend.u.qpsk.symbol_rate, frontend.u.qpsk.fec_inner);
184             break;
185         case FE_QAM:
186             ev = tuneDVB_C_sync(frontend.frequency, frontend.inversion, frontend.u.qam.symbol_rate, frontend.u.qam.fec_inner, frontend.u.qam.modulation);
187             break;
188         case FE_OFDM:
189             ev = tuneDVB_T_sync(frontend.frequency, frontend.inversion, frontend.u.ofdm.bandwidth, frontend.u.ofdm.code_rate_HP, frontend.u.ofdm.code_rate_LP, frontend.u.ofdm.constellation, frontend.u.ofdm.transmission_mode, frontend.u.ofdm.guard_interval, frontend.u.ofdm.hierarchy_information);
190             break;
191         default:
192             SENF_THROW_SYSTEM_EXCEPTION("Could not determine type of card.");
193     }
194     return ev;
195 }
196
197 prefix_ dvb_frontend_event senf::DVBSocketController::tuneDVB_T_sync(unsigned int frequency, 
198                 fe_spectral_inversion_t inversion,
199                 fe_bandwidth_t bandwidth, 
200                 fe_code_rate_t code_rate_HP, /* high priority stream code rate */
201                 fe_code_rate_t code_rate_LP, /* low priority stream code rate */
202                 fe_modulation_t constellation, /* modulation type (see above) */
203                 fe_transmit_mode_t transmission_mode, 
204                 fe_guard_interval_t guard_interval,
205                 fe_hierarchy_t hierarchy_information
206                 )
207 {
208     if(type != FE_OFDM)
209         SENF_THROW_SYSTEM_EXCEPTION("Type of card is: ") << getTypeString() << " for this operation you need a DVB-T Card!";
210     
211     event.disable();
212     
213     frontendHandle.protocol().setNonBlock(false);
214     
215     frontendHandle.protocol().tuneDVB_T(frequency, 
216             inversion, 
217             bandwidth, 
218             code_rate_HP, 
219             code_rate_LP, 
220             constellation, 
221             transmission_mode, 
222             guard_interval, 
223             hierarchy_information);
224     
225     if(!frontendHandle.waitOOBReadable(senf::ClockService::seconds(2)))
226         SENF_THROW_SYSTEM_EXCEPTION("Could not tune to channel!");
227     
228     return frontendHandle.protocol().getEvent();
229 }
230
231 prefix_ dvb_frontend_event senf::DVBSocketController::tuneDVB_S_sync(unsigned int frequency, fe_spectral_inversion_t inversion, unsigned int symbole_rate, fe_code_rate_t code_rate){
232     if(type != FE_QPSK)
233         SENF_THROW_SYSTEM_EXCEPTION("Type of card is: ") << getTypeString() << " for this operation you need a DVB-S Card!";
234     
235     event.disable();
236     
237     frontendHandle.protocol().setNonBlock(false);
238     
239     frontendHandle.protocol().tuneDVB_S(frequency, inversion, symbole_rate, code_rate);
240     
241     if(!frontendHandle.waitOOBReadable(senf::ClockService::seconds(2)))
242         SENF_THROW_SYSTEM_EXCEPTION("Could not tune to channel!");
243     return frontendHandle.protocol().getEvent();
244 }
245
246 prefix_ dvb_frontend_event senf::DVBSocketController::tuneDVB_C_sync(unsigned int frequency, 
247                 fe_spectral_inversion_t inversion,
248                 unsigned int symbol_rate,
249                 fe_code_rate_t fec_inner,
250                 fe_modulation_t modulation
251                 )
252 {   
253     if(type != FE_QAM)
254         SENF_THROW_SYSTEM_EXCEPTION("Type of card is: ") << getTypeString() << " for this operation you need a DVB-C Card!";
255     
256     event.disable();
257     
258     frontendHandle.protocol().setNonBlock(false);
259     
260     frontendHandle.protocol().tuneDVB_C(frequency, inversion, symbol_rate, fec_inner, modulation);
261     if(!frontendHandle.waitOOBReadable(senf::ClockService::seconds(2)))
262         SENF_THROW_SYSTEM_EXCEPTION("Could not tune to channel!");
263
264     return frontendHandle.protocol().getEvent();
265 }
266
267
268 prefix_ string senf::DVBSocketController::getTypeString(){
269     switch (type) {
270         case FE_QPSK:
271             return "DVB-S";
272         case FE_QAM:
273             return "DVB-C";
274         case FE_OFDM:
275             return "DVB-T";
276         default:
277             SENF_THROW_SYSTEM_EXCEPTION("Could not determine type of card.");
278     }
279     
280 }
281 prefix_ unsigned int senf::DVBSocketController::bitErrorRate(){ 
282     return frontendHandle.protocol().bitErrorRate();
283 }
284
285 prefix_ unsigned int senf::DVBSocketController::signalToNoiseRatio(){ 
286     return frontendHandle.protocol().signalNoiseRatio();
287 }
288
289 prefix_ unsigned int senf::DVBSocketController::signalStrength(){ 
290     return frontendHandle.protocol().signalStrength();
291 }
292
293 prefix_ string senf::DVBSocketController::getTuneInfo(const string & conf){
294     const char* cConf = conf.c_str();
295     stringstream info;
296     
297     fe_status_t status;
298     frontendHandle.protocol().setNonBlock(false);
299     uint16_t snr, signal;
300     uint32_t ber, uncorrected_blocks;
301     status = frontendHandle.protocol().status();
302     snr = frontendHandle.protocol().signalNoiseRatio();
303     signal = frontendHandle.protocol().signalStrength();
304     ber = frontendHandle.protocol().bitErrorRate();
305     uncorrected_blocks = frontendHandle.protocol().uncorrectedBlocks();
306     
307     info << hex;
308     
309     for(unsigned int i = 0; i < conf.size(); ++i){
310         if(i>0)
311             info << " | ";
312         switch(cConf[i]){
313             case 'S' :
314                 info << "signal " << signal;
315                 break;
316             case 's' : 
317                 info << "snr " << snr;
318                 break;
319             case 'b' :
320                 info << "ber " << ber;
321                 break;
322             case 'u' :
323                 info << "unc " << uncorrected_blocks;
324                 break;
325             case 'f' :
326                 info << "status: " << status2String(status);
327                 break;
328             default:
329                 break;
330         }
331     }
332     return info.str();
333 }
334 prefix_ string senf::DVBSocketController::status2String(fe_status_t status){
335    string s("");
336     if (status & FE_HAS_LOCK)
337         return s += "HAS LOCK"; 
338     if (status & FE_HAS_CARRIER)
339         s += "HAS CARRIER ";
340     if (status & FE_HAS_VITERBI)
341         s += "HAS VITERBI ";
342     if (status & FE_HAS_SYNC)
343         s += "HAS SYNC ";
344     if (status & FE_HAS_SIGNAL)
345         s += "HAS SIGNAL ";
346     if (status & FE_TIMEDOUT)
347         s += "TIMED OUT ";
348     if (status & FE_REINIT)
349         s += "REINIT ";
350
351     return s;
352 }
353
354 prefix_ void senf::DVBSocketController::setSectionFilter(unsigned short int pid, 
355         u_int8_t filter,
356         unsigned int flags, 
357         u_int8_t mask, 
358         u_int8_t mode,
359         unsigned int timeout)
360 {
361     sectionHandle.protocol().setSectionFilter(pid, timeout, flags, filter, mask, mode);
362     
363 }
364
365 prefix_ void senf::DVBSocketController::setBufferSize(unsigned long size)
366 {
367     sectionHandle.protocol().setBufferSize(size);
368 }
369
370 prefix_ void senf::DVBSocketController::startFiltering()
371 {
372     sectionHandle.protocol().startFiltering();
373 }
374
375 prefix_ void senf::DVBSocketController::stopFiltering()
376 {
377     sectionHandle.protocol().stopFiltering();
378 }
379
380 prefix_ fe_type_t senf::DVBSocketController::getType(){
381     return type;
382 }
383
384 prefix_ void senf::DVBSocketController::readEvent(int event){
385     if(cb)
386         cb(frontendHandle.protocol().getEvent());
387 }
388
389 prefix_ void senf::DVBSocketController::initConsole(){
390     // binding functions to console
391     namespace kw = senf::console::kw;
392     dir.doc("DVB Controller");
393     
394     dir.add("type", &DVBSocketController::getTypeString)
395     .doc("Shows actual type of card DVB-{T, S, C}");
396     
397     dir.add("info", &DVBSocketController::getTuneInfo)
398     .doc("Returns a string which shows actual tuning status.\n\
399             \"S\" prints signal strength (in hex)\n\
400             \"s\" prints singal to noise ration (in hex)\n\
401             \"b\" prints bit error rate (in hex)\n\
402             \"u\" prints uncorrected blocks (in hex)\n\
403             \"f\" prints readable overal status e.g. \"Has Lock\"\n\n\
404             These characters can be used to form the output. Be aware, some\n\
405             features may not be supported be your current driver implementation\n\
406             and could end in throwing an exception!")
407     .arg("conf", "Ssbuf", kw::default_value = "Ssbuf");
408     
409     dir.add("tune", &DVBSocketController::tuneToCMD)
410         .doc("tunes to channel listet in the configfile.")
411         .arg("channel", "channel to tune")
412         .arg("mode", "mode \"sync\" or \"async\"", kw::default_value = "async");
413     
414     dir.add("buffersize", &DVBSocketController::setBufferSize)
415         .doc("Set the size of the circular buffer used for filtered data.")
416         .arg("size", "in byte");
417     
418     dir.add("start", &DVBSocketController::startFiltering)
419         .doc("Starts filtering");
420         
421     dir.add("stop", &DVBSocketController::setBufferSize)
422         .doc("Stops filtering");
423     
424     dir.add("filter", &DVBSocketController::setSectionFilter)
425         .arg("pid", "pid to filter")
426         .arg("filter", "filter", kw::default_value = 62, kw::default_doc   = "0x3e")
427         .arg("flags", "or-able: DMX_CHECK_CRC(0x01), DMX_ONESHOT(0x02), DMX_IMMEDIATE_START(0x04), DMX_KERNEL_CLIENT(0x8000)", kw::default_value = DMX_IMMEDIATE_START | DMX_CHECK_CRC, kw::default_doc   = "0x05")
428         .arg("mask", "mask", kw::default_value = 0xff, kw::default_doc   = "0xff")
429         .arg("mode", "mode", kw::default_value = 0, kw::default_doc   = "0x00")
430         .arg("timeout", "timeout", kw::default_value = 0, kw::default_doc   = "0x00")
431         .doc("Sets parameters for section filter.");
432        
433     dir.add("stop", &DVBSocketController::setBufferSize)
434             .doc("Stops filtering");
435 }