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