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