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