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