fix scan
[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++/terrestrial_delivery_system_descriptor.h>
9 #include <dvbsi++/cable_delivery_system_descriptor.h>
10 #include <dvbsi++/ca_identifier_descriptor.h>
11 #include <lib/dvb/specs.h>
12 #include <lib/dvb/esection.h>
13 #include <lib/dvb/scan.h>
14 #include <lib/dvb/frontend.h>
15 #include <lib/base/eerror.h>
16 #include <lib/base/estring.h>
17 #include <errno.h>
18
19 static bool scan_debug;
20 #define SCAN_eDebug(x...) do { if (scan_debug) eDebug(x); } while(0)
21 #define SCAN_eDebugNoNewLine(x...) do { if (scan_debug) eDebugNoNewLine(x); } while(0)
22
23 DEFINE_REF(eDVBScan);
24
25 eDVBScan::eDVBScan(iDVBChannel *channel, bool debug)
26         :m_channel(channel), m_channel_state(iDVBChannel::state_idle)
27         ,m_ready(0), m_ready_all(readySDT), m_flags(0)
28 {
29         scan_debug=debug;
30         if (m_channel->getDemux(m_demux))
31                 SCAN_eDebug("scan: failed to allocate demux!");
32         m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
33 }
34
35 eDVBScan::~eDVBScan()
36 {
37 }
38
39 int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid)
40 {
41         switch (onid.get())
42         {
43         case 0:
44         case 0x1111:
45                 return 0;
46         case 1:
47                 return orbital_position == 192;
48         case 0x00B1:
49                 return tsid != 0x00B0;
50         case 0x0002:
51                 return abs(orbital_position-282) < 6;
52         default:
53                 return onid.get() < 0xFF00;
54         }
55 }
56
57 eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
58 {
59                 // on valid ONIDs, ignore frequency ("sub network") part
60         if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid))
61                 hash &= ~0xFFFF;
62         return eDVBNamespace(hash);
63 }
64
65 void eDVBScan::stateChange(iDVBChannel *ch)
66 {
67         int state;
68         if (ch->getState(state))
69                 return;
70         if (m_channel_state == state)
71                 return;
72         
73         if (state == iDVBChannel::state_ok)
74         {
75                 startFilter();
76                 m_channel_state = state;
77         } else if (state == iDVBChannel::state_failed)
78         {
79                 m_ch_unavailable.push_back(m_ch_current);
80                 nextChannel();
81         }
82                         /* unavailable will timeout, anyway. */
83 }
84
85 RESULT eDVBScan::nextChannel()
86 {
87         ePtr<iDVBFrontend> fe;
88
89         m_SDT = 0; m_BAT = 0; m_NIT = 0;
90
91         m_ready = 0;
92         
93                 /* check what we need */
94         m_ready_all = readySDT;
95         
96         if (m_flags & scanNetworkSearch)
97                 m_ready_all |= readyNIT;
98         
99         if (m_flags & scanSearchBAT)
100                 m_ready_all |= readyBAT;
101         
102         if (m_ch_toScan.empty())
103         {
104                 SCAN_eDebug("no channels left to scan.");
105                 SCAN_eDebug("%d channels scanned, %d were unavailable.", 
106                                 m_ch_scanned.size(), m_ch_unavailable.size());
107                 SCAN_eDebug("%d channels in database.", m_new_channels.size());
108                 m_event(evtFinish);
109                 return -ENOENT;
110         }
111         
112         m_ch_current = m_ch_toScan.front();
113         
114         m_ch_toScan.pop_front();
115         
116         if (m_channel->getFrontend(fe))
117         {
118                 m_event(evtFail);
119                 return -ENOTSUP;
120         }
121
122         int fetype;
123         fe->getFrontendType(fetype);
124         if ( fetype == iDVBFrontend::feSatellite)
125         {
126                 eDVBFrontendParametersSatellite p;
127                 m_ch_current->getDVBS(p);
128                 m_chid_current = eDVBChannelID(p.orbital_position << 16, -1, -1);
129         }
130         else
131                 m_chid_current = eDVBChannelID();
132
133         m_channel_state = iDVBChannel::state_idle;
134         if (fe->tune(*m_ch_current))
135         {
136                 return nextChannel();
137                 m_event(evtFail);
138                 return -EINVAL;
139         }
140                 
141         m_event(evtUpdate);
142         return 0;
143 }
144
145 RESULT eDVBScan::startFilter()
146 {
147         assert(m_demux);
148         
149                         /* only start required filters filter */
150         
151         m_SDT = 0;
152
153         if (m_ready_all & readySDT)
154         {
155                 m_SDT = new eTable<ServiceDescriptionSection>();
156                 if (m_SDT->start(m_demux, eDVBSDTSpec()))
157                         return -1;
158                 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
159         }
160
161         m_NIT = 0;
162         if (m_ready_all & readyNIT)
163         {
164                 m_NIT = new eTable<NetworkInformationSection>();
165                 if (m_NIT->start(m_demux, eDVBNITSpec()))
166                         return -1;
167                 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
168         }
169
170         m_BAT = 0;
171         if (m_ready_all & readyBAT)
172         {
173                 m_BAT = new eTable<BouquetAssociationSection>();
174                 if (m_BAT->start(m_demux, eDVBBATSpec()))
175                         return -1;
176                 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
177         }
178         
179         return 0;
180 }
181
182 void eDVBScan::SDTready(int err)
183 {
184         SCAN_eDebug("got sdt");
185         m_ready |= readySDT;
186         if (!err)
187                 m_ready |= validSDT;
188         channelDone();
189 }
190
191 void eDVBScan::NITready(int err)
192 {
193         SCAN_eDebug("got nit, err %d", err);
194         m_ready |= readyNIT;
195         if (!err)
196                 m_ready |= validNIT;
197         channelDone();
198 }
199
200 void eDVBScan::BATready(int err)
201 {
202         SCAN_eDebug("got bat");
203         m_ready |= readyBAT;
204         if (!err)
205                 m_ready |= validBAT;
206         channelDone();
207 }
208
209 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
210 {
211                 /* add it to the list of known channels. */
212         if (chid)
213                 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
214 }
215
216 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
217 {
218                 /* check if we don't already have that channel ... */
219                 
220                 /* ... in the list of channels to scan */
221         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
222                 if (sameChannel(*i, feparm))
223                         return;
224
225                 /* ... in the list of successfully scanned channels */
226         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
227                 if (sameChannel(*i, feparm))
228                         return;
229                 
230                 /* ... in the list of unavailable channels */
231         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
232                 if (sameChannel(*i, feparm))
233                         return;
234
235                 /* ... on the current channel */
236         if (sameChannel(m_ch_current, feparm))
237                 return;
238
239                 /* otherwise, add it to the todo list. */
240         m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
241 }
242
243 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
244 {
245         int diff;
246         if (ch1->calculateDifference(ch2, diff))
247                 return 0;
248         if (diff < 4000) // more than 4mhz difference?
249                 return 1;
250         return 0;
251 }
252
253 void eDVBScan::channelDone()
254 {
255         if (m_ready & validSDT)
256         {
257                 unsigned long hash = 0;
258
259                 // m_ch_current is not set, when eDVBScan is just used for a SDT update
260                 if (!m_ch_current)
261                         m_channel->getCurrentFrontendParameters(m_ch_current);
262
263                 m_ch_current->getHash(hash);
264                 
265                 eDVBNamespace dvbnamespace = buildNamespace(
266                         (**m_SDT->getSections().begin()).getOriginalNetworkId(),
267                         (**m_SDT->getSections().begin()).getTransportStreamId(),
268                         hash);
269                 
270                 SCAN_eDebug("SDT: ");
271                 std::vector<ServiceDescriptionSection*>::const_iterator i;
272                 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
273                         processSDT(dvbnamespace, **i);
274                 m_ready &= ~validSDT;
275         }
276         
277         if (m_ready & validNIT)
278         {
279                 SCAN_eDebug("dumping NIT");
280                 std::vector<NetworkInformationSection*>::const_iterator i;
281                 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
282                 {
283                         const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
284                         
285                         for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin()); 
286                                 tsinfo != tsinfovec.end(); ++tsinfo)
287                         {
288                                 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
289                                         (*tsinfo)->getOriginalNetworkId());
290                                 
291                                 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
292                                 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
293                                 
294                                 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
295                                                 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
296                                 {
297                                         switch ((*desc)->getTag())
298                                         {
299                                         case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
300                                         {
301                                                 CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
302                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
303                                                 eDVBFrontendParametersCable cable;
304                                                 cable.set(d);
305                                                 feparm->setDVBC(cable);
306
307                                                 unsigned long hash=0;
308                                                 feparm->getHash(hash);
309                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
310
311                                                 addChannelToScan(
312                                                         eDVBChannelID(ns, tsid, onid),
313                                                         feparm);
314                                                 break;
315                                         }
316                                         case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
317                                         {
318                                                 TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
319                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
320                                                 eDVBFrontendParametersTerrestrial terr;
321                                                 terr.set(d);
322                                                 feparm->setDVBT(terr);
323
324                                                 unsigned long hash=0;
325                                                 feparm->getHash(hash);
326                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
327
328                                                 addChannelToScan(
329                                                         eDVBChannelID(ns, tsid, onid),
330                                                         feparm);
331                                                 break;
332                                         }
333                                         case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
334                                         {
335                                                 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
336                                                 if (d.getFrequency() < 10000)
337                                                         break;
338                                                 
339                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
340                                                 eDVBFrontendParametersSatellite sat;
341                                                 sat.set(d);
342                                                 feparm->setDVBS(sat);
343                                                 unsigned long hash=0;
344                                                 feparm->getHash(hash);
345                                                 
346                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
347                                                 
348                                                 if ( m_chid_current.dvbnamespace.get() != -1 &&
349                                                         ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
350                                                         SCAN_eDebug("dropping this transponder, it's on another satellite.");
351                                                 else
352                                                 {
353                                                         addChannelToScan(
354                                                                         eDVBChannelID(ns, tsid, onid),
355                                                                         feparm);
356                                                 }
357                                                 break;
358                                         }
359                                         default:
360                                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
361                                                 break;
362                                         }
363                                 }
364                                 
365                         }
366                 }
367                 m_ready &= ~validNIT;
368         }
369         
370         if ((m_ready  & m_ready_all) != m_ready_all)
371                 return;
372         SCAN_eDebug("channel done!");
373         
374                 /* if we had services on this channel, we declare
375                    this channels as "known good". add it.
376                    
377                    (TODO: not yet implemented)
378                    a NIT entry could have possible overridden
379                    our frontend data with more exact data.
380                    
381                    (TODO: not yet implemented)
382                    the tuning process could have lead to more
383                    exact data than the user entered.
384                    
385                    The channel id was probably corrected
386                    by the data written in the SDT. this is
387                    important, as "initial transponder lists"
388                    usually don't have valid CHIDs (and that's
389                    good).
390                    
391                    These are the reasons for adding the transponder
392                    here, and not before.
393                 */
394
395         if (!m_chid_current)
396                 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
397         else
398                 addKnownGoodChannel(m_chid_current, m_ch_current);
399         
400         m_ch_scanned.push_back(m_ch_current);
401         nextChannel();
402 }
403
404 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
405 {
406         m_flags = flags;
407         m_ch_toScan.clear();
408         m_ch_scanned.clear();
409         m_ch_unavailable.clear();
410         m_new_channels.clear();
411         m_new_services.clear();
412         m_last_service = m_new_services.end();
413
414         for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
415         {
416                 bool exist=false;
417                 for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
418                 {
419                         if (sameChannel(*i, *ii))
420                         {
421                                 exist=true;
422                                 break;
423                         }
424                 }
425                 if (!exist)
426                         m_ch_toScan.push_back(*i);
427         }
428
429         nextChannel();
430 }
431
432 void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
433 {
434         if (m_flags & scanRemoveServices)
435         {
436                 bool clearTerrestrial=false;
437                 bool clearCable=false;
438                 std::set<unsigned int> scanned_sat_positions;
439                 
440                 std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
441                 for (;it != m_ch_scanned.end(); ++it)
442                 {
443                         int system;
444                         (*it)->getSystem(system);
445                         switch(system)
446                         {
447                                 case iDVBFrontend::feSatellite:
448                                 {
449                                         eDVBFrontendParametersSatellite sat_parm;
450                                         (*it)->getDVBS(sat_parm);
451                                         scanned_sat_positions.insert(sat_parm.orbital_position);
452                                         break;
453                                 }
454                                 case iDVBFrontend::feTerrestrial:
455                                 {
456                                         clearTerrestrial=true;
457                                         break;
458                                 }
459                                 case iDVBFrontend::feCable:
460                                 {
461                                         clearCable=true;
462                                         break;
463                                 }
464                         }
465                 }
466
467                 for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
468                 {
469                         int system;
470                         (*it)->getSystem(system);
471                         switch(system)
472                         {
473                                 case iDVBFrontend::feSatellite:
474                                 {
475                                         eDVBFrontendParametersSatellite sat_parm;
476                                         (*it)->getDVBS(sat_parm);
477                                         scanned_sat_positions.insert(sat_parm.orbital_position);
478                                         break;
479                                 }
480                                 case iDVBFrontend::feTerrestrial:
481                                 {
482                                         clearTerrestrial=true;
483                                         break;
484                                 }
485                                 case iDVBFrontend::feCable:
486                                 {
487                                         clearCable=true;
488                                         break;
489                                 }
490                         }
491                 }
492
493                 if (clearTerrestrial)
494                 {
495                         eDVBChannelID chid;
496                         chid.dvbnamespace=0xEEEE0000;
497                         db->removeServices(chid);
498                 }
499                 if (clearCable)
500                 {
501                         eDVBChannelID chid;
502                         chid.dvbnamespace=0xFFFF0000;
503                         db->removeServices(chid);
504                 }
505                 for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
506                 {
507                         eDVBChannelID chid;
508                         if (m_flags & scanDontRemoveFeeds)
509                                 chid.dvbnamespace = eDVBNamespace((*x)<<16);
510 //                      eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
511                         db->removeServices(chid, *x);
512                 }
513         }
514
515         for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator 
516                         ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
517                 db->addChannelToList(ch->first, ch->second);
518         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
519                 service(m_new_services.begin()); service != m_new_services.end(); ++service)
520         {
521                 ePtr<eDVBService> dvb_service;
522                 if (!db->getService(service->first, dvb_service))
523                 {
524                         if (dvb_service->m_flags & eDVBService::dxNoSDT)
525                                 continue;
526                         if (!(dvb_service->m_flags & eDVBService::dxHoldName))
527                         {
528                                 dvb_service->m_service_name = service->second->m_service_name;
529                                 dvb_service->m_service_name_sort = service->second->m_service_name_sort;
530                         }
531                         dvb_service->m_provider_name = service->second->m_provider_name;
532                         if (service->second->m_ca.size())
533                                 dvb_service->m_ca = service->second->m_ca;
534                         if (!dontRemoveOldFlags) // do not remove new found flags when not wished
535                                 dvb_service->m_flags &= ~eDVBService::dxNewFound;
536                 }
537                 else
538                 {
539                         db->addService(service->first, service->second);
540                         service->second->m_flags |= eDVBService::dxNewFound;
541                 }
542         }
543 }
544
545 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
546 {
547         const ServiceDescriptionList &services = *sdt.getDescriptions();
548         SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
549         eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
550         
551                 /* save correct CHID for this channel if this is an ACTUAL_SDT */
552         if (sdt.getTableId() == TID_SDT_ACTUAL)
553                 m_chid_current = chid;
554         
555         for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
556         {
557                 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
558
559                 eServiceReferenceDVB ref;
560                 ePtr<eDVBService> service = new eDVBService;
561                 
562                 ref.set(chid);
563                 ref.setServiceID((*s)->getServiceId());
564
565                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
566                                 desc != (*s)->getDescriptors()->end(); ++desc)
567                         if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
568                                 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
569                 
570                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
571                                 desc != (*s)->getDescriptors()->end(); ++desc)
572                 {
573                         switch ((*desc)->getTag())
574                         {
575                         case SERVICE_DESCRIPTOR:
576                         {
577                                 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
578                                 service->m_service_name = convertDVBUTF8(d.getServiceName());
579                                 service->genSortName();
580
581                                 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
582                                 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
583                                 break;
584                         }
585                         case CA_IDENTIFIER_DESCRIPTOR:
586                         {
587                                 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
588                                 const CaSystemIdList &caids = *d.getCaSystemIds();
589                                 SCAN_eDebugNoNewLine("CA ");
590                                 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
591                                 {
592                                         SCAN_eDebugNoNewLine("%04x ", *i);
593                                         service->m_ca.push_front(*i);
594                                 }
595                                 SCAN_eDebug("");
596                                 break;
597                         }
598                         default:
599                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
600                                 break;
601                         }
602                 }
603                 
604                 std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
605                 
606                 if (i.second)
607                 {
608                         m_last_service = i.first;
609                         m_event(evtNewService);
610                 }
611         }
612         return 0;
613 }
614
615 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
616 {
617         connection = new eConnection(this, m_event.connect(event));
618         return 0;
619 }
620
621 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
622 {
623         transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
624         transponders_total = m_ch_toScan.size() + transponders_done;
625         services = m_new_services.size();
626 }
627
628 void eDVBScan::getLastServiceName(std::string &last_service_name)
629 {
630         if (m_last_service == m_new_services.end())
631                 last_service_name = "";
632         else
633                 last_service_name = m_last_service->second->m_service_name;
634 }