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