added Lcd.py
[enigma2.git] / lib / dvb / scan.cpp
1 #include <lib/dvb/idvb.h>
2 #include <dvbsi++/service_description_section.h>
3 #include <dvbsi++/network_information_section.h>
4 #include <dvbsi++/bouquet_association_section.h>
5 #include <dvbsi++/descriptor_tag.h>
6 #include <dvbsi++/service_descriptor.h>
7 #include <dvbsi++/satellite_delivery_system_descriptor.h>
8 #include <dvbsi++/ca_identifier_descriptor.h>
9 #include <lib/dvb/specs.h>
10 #include <lib/dvb/esection.h>
11 #include <lib/dvb/scan.h>
12 #include <lib/dvb/frontend.h>
13 #include <lib/base/eerror.h>
14 #include <lib/base/estring.h>
15 #include <errno.h>
16
17 #define SCAN_eDebug(x...) eDebug(x)
18 #define SCAN_eDebugNoNewLine(x...) eDebugNoNewLine(x)
19
20 DEFINE_REF(eDVBScan);
21
22 eDVBScan::eDVBScan(iDVBChannel *channel): m_channel(channel)
23 {
24         if (m_channel->getDemux(m_demux))
25                 SCAN_eDebug("scan: failed to allocate demux!");
26         m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
27 }
28
29 eDVBScan::~eDVBScan()
30 {
31 }
32
33 int eDVBScan::isValidONIDTSID(eOriginalNetworkID onid, eTransportStreamID tsid)
34 {
35         switch (onid.get())
36         {
37         case 0:
38         case 0xFFFF:
39         case 0x1111:
40                 return 0;
41         case 1:
42                 return tsid>1;
43         case 0x00B1:
44                 return tsid != 0x00B0;
45         case 0x0002:
46                 return tsid != 0x07E8;
47         default:
48                 return 1;
49         }
50 }
51
52 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
53 {
54                 // on valid ONIDs, ignore frequency ("sub network") part
55         if (isValidONIDTSID(onid, tsid))
56                 hash &= ~0xFFFF;
57         return eDVBNamespace(hash);
58 }
59
60 void eDVBScan::stateChange(iDVBChannel *ch)
61 {
62         int state;
63         if (ch->getState(state))
64                 return;
65         if (m_channel_state == state)
66                 return;
67         
68         if (state == iDVBChannel::state_ok)
69         {
70                 startFilter();
71                 m_channel_state = state;
72         } else if (state == iDVBChannel::state_unavailable)
73         {
74                 m_ch_unavailable.push_back(m_ch_current);
75                 nextChannel();
76         }
77 }
78
79 RESULT eDVBScan::nextChannel()
80 {
81         ePtr<iDVBFrontend> fe;
82
83         m_SDT = 0; m_BAT = 0; m_NIT = 0;
84
85         m_ready = readyBAT;
86         if (m_ch_toScan.empty())
87         {
88                 eDebug("no channels left to scan.");
89                 eDebug("%d channels scanned, %d were unavailable.", 
90                                 m_ch_scanned.size(), m_ch_unavailable.size());
91                 eDebug("%d channels in database.", m_new_channels.size());
92                 m_event(evtFinish);
93                 return -ENOENT;
94         }
95         
96         m_ch_current = m_ch_toScan.front();
97         m_chid_current = eDVBChannelID();
98         
99         m_ch_toScan.pop_front();
100         
101         if (m_channel->getFrontend(fe))
102         {
103                 m_event(evtFail);
104                 return -ENOTSUP;
105         }
106         
107         m_channel_state = iDVBChannel::state_idle;
108         if (fe->tune(*m_ch_current))
109         {
110                 return nextChannel();
111                 m_event(evtFail);
112                 return -EINVAL;
113         }
114                 
115         m_event(evtUpdate);
116         return 0;
117 }
118
119 RESULT eDVBScan::startFilter()
120 {
121         assert(m_demux);
122         
123         m_SDT = new eTable<ServiceDescriptionSection>();
124         if (m_SDT->start(m_demux, eDVBSDTSpec()))
125                 return -1;
126         CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
127
128         m_NIT = 0;
129         m_NIT = new eTable<NetworkInformationSection>();
130         if (m_NIT->start(m_demux, eDVBNITSpec()))
131                 return -1;
132         CONNECT(m_NIT->tableReady, eDVBScan::NITready);
133         
134         m_BAT = new eTable<BouquetAssociationSection>();
135         if (m_BAT->start(m_demux, eDVBBATSpec()))
136                 return -1;
137         CONNECT(m_BAT->tableReady, eDVBScan::BATready);
138         
139         return 0;
140 }
141
142 void eDVBScan::SDTready(int err)
143 {
144         SCAN_eDebug("got sdt");
145         m_ready |= readySDT;
146         if (!err)
147                 m_ready |= validSDT;
148         channelDone();
149 }
150
151 void eDVBScan::NITready(int err)
152 {
153         SCAN_eDebug("got nit, err %d", err);
154         m_ready |= readyNIT;
155         if (!err)
156                 m_ready |= validNIT;
157         channelDone();
158 }
159
160 void eDVBScan::BATready(int err)
161 {
162         SCAN_eDebug("got bat");
163         m_ready |= readyBAT;
164         if (!err)
165                 m_ready |= validBAT;
166         channelDone();
167 }
168
169 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
170 {
171                 /* add it to the list of known channels. */
172         if (chid)
173                 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
174 }
175
176 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
177 {
178                 /* check if we don't already have that channel ... */
179                 
180                 /* ... in the list of channels to scan */
181         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
182                 if (sameChannel(*i, feparm))
183                         return;
184
185                 /* ... in the list of successfully scanned channels */
186         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
187                 if (sameChannel(*i, feparm))
188                         return;
189                 
190                 /* ... in the list of unavailable channels */
191         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
192                 if (sameChannel(*i, feparm))
193                         return;
194
195                 /* ... on the current channel */
196         if (sameChannel(m_ch_current, feparm))
197                 return;
198
199                 /* otherwise, add it to the todo list. */
200         m_ch_toScan.push_back(feparm);
201 }
202
203 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
204 {
205         int diff;
206         if (ch1->calculateDifference(ch2, diff))
207                 return 0;
208         if (diff < 4000) // more than 4mhz difference?
209                 return 1;
210         return 0;
211 }
212
213 void eDVBScan::channelDone()
214 {
215         if (m_ready & validSDT)
216         {
217                 unsigned long hash = 0;
218                 m_ch_current->getHash(hash);
219                 
220                 eDVBNamespace dvbnamespace = buildNamespace(
221                         (**m_SDT->getSections().begin()).getOriginalNetworkId(),
222                         (**m_SDT->getSections().begin()).getTransportStreamId(),
223                         hash);
224                 
225                 SCAN_eDebug("SDT: ");
226                 std::vector<ServiceDescriptionSection*>::const_iterator i;
227                 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
228                         processSDT(dvbnamespace, **i);
229                 m_ready &= ~validSDT;
230         }
231         
232         if (m_ready & validNIT)
233         {
234                 SCAN_eDebug("dumping NIT");
235                 std::vector<NetworkInformationSection*>::const_iterator i;
236                 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
237                 {
238                         const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
239                         
240                         for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin()); 
241                                 tsinfo != tsinfovec.end(); ++tsinfo)
242                         {
243                                 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
244                                         (*tsinfo)->getOriginalNetworkId());
245                                 
246                                 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
247                                 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
248                                 
249                                 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
250                                                 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
251                                 {
252                                         switch ((*desc)->getTag())
253                                         {
254 //                                      case SERVICE_LIST_DESCRIPTOR:
255                                         case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
256                                         {
257                                                 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
258                                                 SCAN_eDebug("%d kHz, %d%d%d.%d%c %s MOD:%d %d symb/s, fec %d", 
259                                                                 d.getFrequency(), 
260                                                                 (d.getOrbitalPosition()>>12)&0xF,
261                                                                 (d.getOrbitalPosition()>>8)&0xF,
262                                                                 (d.getOrbitalPosition()>>4)&0xF,
263                                                                 d.getOrbitalPosition()&0xF, d.getWestEastFlag()?'E':'W',
264                                                                 d.getPolarization() ? "hor" : "vert",
265                                                                 d.getModulation(), d.getSymbolRate(), d.getFecInner());
266                                                 
267                                                         /* some sanity checking: below 100MHz is invalid */
268                                                 if (d.getFrequency() < 10000)
269                                                         break;
270                                                 
271                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
272                                                 eDVBFrontendParametersSatellite sat;
273                                                 sat.set(d);
274                                                 feparm->setDVBS(sat);
275                                                 unsigned long hash=0;
276                                                 feparm->getHash(hash);
277                                                 
278                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
279
280                                                 addChannelToScan(
281                                                                 eDVBChannelID(ns, tsid, onid),
282                                                                 feparm);
283                                                 break;
284                                         }
285                                         default:
286                                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
287                                                 break;
288                                         }
289                                 }
290                                 
291                         }
292                 }
293                 m_ready &= ~validNIT;
294         }
295         
296         if ((m_ready  & readyAll) != readyAll)
297                 return;
298         SCAN_eDebug("channel done!");
299         
300                 /* if we had services on this channel, we declare
301                    this channels as "known good". add it.
302                    
303                    (TODO: not yet implemented)
304                    a NIT entry could have possible overridden
305                    our frontend data with more exact data.
306                    
307                    (TODO: not yet implemented)
308                    the tuning process could have lead to more
309                    exact data than the user entered.
310                    
311                    The channel id was probably corrected
312                    by the data written in the SDT. this is
313                    important, as "initial transponder lists"
314                    usually don't have valid CHIDs (and that's
315                    good).
316                    
317                    These are the reasons for adding the transponder
318                    here, and not before.
319                 */
320         
321         if (!m_chid_current)
322                 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
323         else
324                 addKnownGoodChannel(m_chid_current, m_ch_current);
325         
326         m_ch_scanned.push_back(m_ch_current);
327         nextChannel();
328 }
329
330 void eDVBScan::start(const std::list<ePtr<iDVBFrontendParameters> > &known_transponders)
331 {
332         m_ch_toScan.clear();
333         m_ch_scanned.clear();
334         m_ch_unavailable.clear();
335         m_new_channels.clear();
336         m_new_services.clear();
337         m_ch_toScan.insert(m_ch_toScan.end(), known_transponders.begin(), known_transponders.end());
338         nextChannel();
339 }
340
341 void eDVBScan::insertInto(iDVBChannelList *db)
342 {
343         for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator 
344                         ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
345                 db->addChannelToList(ch->first, ch->second);
346         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
347                 service(m_new_services.begin()); service != m_new_services.end(); ++service)
348         {
349                 ePtr<eDVBService> dvb_service;
350                 if (!db->getService(service->first, dvb_service))
351                         *dvb_service = *service->second;
352                 else
353                         db->addService(service->first, service->second);
354         }
355 }
356
357 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
358 {
359         const ServiceDescriptionList &services = *sdt.getDescriptions();
360         SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
361         eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
362         
363                 /* save correct CHID for this channel if this is an ACTUAL_SDT */
364         if (sdt.getTableId() == TID_SDT_ACTUAL)
365                 m_chid_current = chid;
366         
367         for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
368         {
369                 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
370
371                 eServiceReferenceDVB ref;
372                 ePtr<eDVBService> service = new eDVBService;
373                 
374                 ref.set(chid);
375                 ref.setServiceID((*s)->getServiceId());
376
377                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
378                                 desc != (*s)->getDescriptors()->end(); ++desc)
379                         if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
380                                 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
381                 
382                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
383                                 desc != (*s)->getDescriptors()->end(); ++desc)
384                 {
385                         switch ((*desc)->getTag())
386                         {
387                         case SERVICE_DESCRIPTOR:
388                         {
389                                 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
390                                 service->m_service_name = convertDVBUTF8(d.getServiceName());
391                                 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
392                                 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
393                                 break;
394                         }
395                         case CA_IDENTIFIER_DESCRIPTOR:
396                         {
397                                 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
398                                 const CaSystemIdList &caids = *d.getCaSystemIds();
399                                 SCAN_eDebugNoNewLine("CA ");
400                                 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
401                                 {
402                                         SCAN_eDebugNoNewLine("%04x ", *i);
403                                         service->m_ca.insert(*i);
404                                 }
405                                 SCAN_eDebug("");
406                                 break;
407                         }
408                         default:
409                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
410                                 break;
411                         }
412                 }
413                 
414                 m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));               
415         }
416         return 0;
417 }
418
419 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
420 {
421         connection = new eConnection(this, m_event.connect(event));
422         return 0;
423 }
424
425 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
426 {
427         transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
428         transponders_total = m_ch_toScan.size() + transponders_done;
429         services = m_new_services.size();
430 }