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