1c98dce0a613471744eebf3523da9af30601afcc
[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_failed)
73         {
74                 m_ch_unavailable.push_back(m_ch_current);
75                 nextChannel();
76         }
77                         /* unavailable will timeout, anyway. */
78 }
79
80 RESULT eDVBScan::nextChannel()
81 {
82         ePtr<iDVBFrontend> fe;
83
84         m_SDT = 0; m_BAT = 0; m_NIT = 0;
85
86         m_ready = 0;
87         
88                 /* check what we need */
89         m_ready_all = readySDT;
90         
91         if (m_flags & scanNetworkSearch)
92                 m_ready_all |= readyNIT;
93         
94         if (m_flags & scanSearchBAT)
95                 m_ready_all |= readyBAT;
96         
97         if (m_ch_toScan.empty())
98         {
99                 eDebug("no channels left to scan.");
100                 eDebug("%d channels scanned, %d were unavailable.", 
101                                 m_ch_scanned.size(), m_ch_unavailable.size());
102                 eDebug("%d channels in database.", m_new_channels.size());
103                 m_event(evtFinish);
104                 return -ENOENT;
105         }
106         
107         m_ch_current = m_ch_toScan.front();
108         m_chid_current = eDVBChannelID();
109         
110         m_ch_toScan.pop_front();
111         
112         if (m_channel->getFrontend(fe))
113         {
114                 m_event(evtFail);
115                 return -ENOTSUP;
116         }
117         
118         m_channel_state = iDVBChannel::state_idle;
119         if (fe->tune(*m_ch_current))
120         {
121                 return nextChannel();
122                 m_event(evtFail);
123                 return -EINVAL;
124         }
125                 
126         m_event(evtUpdate);
127         return 0;
128 }
129
130 RESULT eDVBScan::startFilter()
131 {
132         assert(m_demux);
133         
134                         /* only start required filters filter */
135         
136         m_SDT = 0;
137
138         if (m_ready_all & readySDT)
139         {
140                 m_SDT = new eTable<ServiceDescriptionSection>();
141                 if (m_SDT->start(m_demux, eDVBSDTSpec()))
142                         return -1;
143                 CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
144         }
145
146         m_NIT = 0;
147         if (m_ready_all & readyNIT)
148         {
149                 m_NIT = new eTable<NetworkInformationSection>();
150                 if (m_NIT->start(m_demux, eDVBNITSpec()))
151                         return -1;
152                 CONNECT(m_NIT->tableReady, eDVBScan::NITready);
153         }
154
155         m_BAT = 0;
156         if (m_ready_all & readyBAT)
157         {
158                 m_BAT = new eTable<BouquetAssociationSection>();
159                 if (m_BAT->start(m_demux, eDVBBATSpec()))
160                         return -1;
161                 CONNECT(m_BAT->tableReady, eDVBScan::BATready);
162         }
163         
164         return 0;
165 }
166
167 void eDVBScan::SDTready(int err)
168 {
169         SCAN_eDebug("got sdt");
170         m_ready |= readySDT;
171         if (!err)
172                 m_ready |= validSDT;
173         channelDone();
174 }
175
176 void eDVBScan::NITready(int err)
177 {
178         SCAN_eDebug("got nit, err %d", err);
179         m_ready |= readyNIT;
180         if (!err)
181                 m_ready |= validNIT;
182         channelDone();
183 }
184
185 void eDVBScan::BATready(int err)
186 {
187         SCAN_eDebug("got bat");
188         m_ready |= readyBAT;
189         if (!err)
190                 m_ready |= validBAT;
191         channelDone();
192 }
193
194 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
195 {
196                 /* add it to the list of known channels. */
197         if (chid)
198                 m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
199 }
200
201 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
202 {
203                 /* check if we don't already have that channel ... */
204                 
205                 /* ... in the list of channels to scan */
206         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
207                 if (sameChannel(*i, feparm))
208                         return;
209
210                 /* ... in the list of successfully scanned channels */
211         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
212                 if (sameChannel(*i, feparm))
213                         return;
214                 
215                 /* ... in the list of unavailable channels */
216         for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
217                 if (sameChannel(*i, feparm))
218                         return;
219
220                 /* ... on the current channel */
221         if (sameChannel(m_ch_current, feparm))
222                 return;
223
224                 /* otherwise, add it to the todo list. */
225         m_ch_toScan.push_back(feparm);
226 }
227
228 int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
229 {
230         int diff;
231         if (ch1->calculateDifference(ch2, diff))
232                 return 0;
233         if (diff < 4000) // more than 4mhz difference?
234                 return 1;
235         return 0;
236 }
237
238 void eDVBScan::channelDone()
239 {
240         if (m_ready & validSDT)
241         {
242                 unsigned long hash = 0;
243                 m_ch_current->getHash(hash);
244                 
245                 eDVBNamespace dvbnamespace = buildNamespace(
246                         (**m_SDT->getSections().begin()).getOriginalNetworkId(),
247                         (**m_SDT->getSections().begin()).getTransportStreamId(),
248                         hash);
249                 
250                 SCAN_eDebug("SDT: ");
251                 std::vector<ServiceDescriptionSection*>::const_iterator i;
252                 for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
253                         processSDT(dvbnamespace, **i);
254                 m_ready &= ~validSDT;
255         }
256         
257         if (m_ready & validNIT)
258         {
259                 SCAN_eDebug("dumping NIT");
260                 std::vector<NetworkInformationSection*>::const_iterator i;
261                 for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
262                 {
263                         const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo();
264                         
265                         for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin()); 
266                                 tsinfo != tsinfovec.end(); ++tsinfo)
267                         {
268                                 SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
269                                         (*tsinfo)->getOriginalNetworkId());
270                                 
271                                 eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
272                                 eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
273                                 
274                                 for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
275                                                 desc != (*tsinfo)->getDescriptors()->end(); ++desc)
276                                 {
277                                         switch ((*desc)->getTag())
278                                         {
279 //                                      case SERVICE_LIST_DESCRIPTOR:
280                                         case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
281                                         {
282                                                 SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
283                                                 SCAN_eDebug("%d kHz, %d%d%d.%d%c %s MOD:%d %d symb/s, fec %d", 
284                                                                 d.getFrequency(), 
285                                                                 (d.getOrbitalPosition()>>12)&0xF,
286                                                                 (d.getOrbitalPosition()>>8)&0xF,
287                                                                 (d.getOrbitalPosition()>>4)&0xF,
288                                                                 d.getOrbitalPosition()&0xF, d.getWestEastFlag()?'E':'W',
289                                                                 d.getPolarization() ? "hor" : "vert",
290                                                                 d.getModulation(), d.getSymbolRate(), d.getFecInner());
291                                                 
292                                                         /* some sanity checking: below 100MHz is invalid */
293                                                 if (d.getFrequency() < 10000)
294                                                         break;
295                                                 
296                                                 ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
297                                                 eDVBFrontendParametersSatellite sat;
298                                                 sat.set(d);
299                                                 feparm->setDVBS(sat);
300                                                 unsigned long hash=0;
301                                                 feparm->getHash(hash);
302                                                 
303                                                 eDVBNamespace ns = buildNamespace(onid, tsid, hash);
304                                                 
305                                                 if (m_chid_current && ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
306                                                         eDebug("dropping this transponder, it's on another satellite.");
307                                                 else
308                                                 {
309                                                         addChannelToScan(
310                                                                         eDVBChannelID(ns, tsid, onid),
311                                                                         feparm);
312                                                 }
313                                                 break;
314                                         }
315                                         default:
316                                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
317                                                 break;
318                                         }
319                                 }
320                                 
321                         }
322                 }
323                 m_ready &= ~validNIT;
324         }
325         
326         if ((m_ready  & m_ready_all) != m_ready_all)
327                 return;
328         SCAN_eDebug("channel done!");
329         
330                 /* if we had services on this channel, we declare
331                    this channels as "known good". add it.
332                    
333                    (TODO: not yet implemented)
334                    a NIT entry could have possible overridden
335                    our frontend data with more exact data.
336                    
337                    (TODO: not yet implemented)
338                    the tuning process could have lead to more
339                    exact data than the user entered.
340                    
341                    The channel id was probably corrected
342                    by the data written in the SDT. this is
343                    important, as "initial transponder lists"
344                    usually don't have valid CHIDs (and that's
345                    good).
346                    
347                    These are the reasons for adding the transponder
348                    here, and not before.
349                 */
350         
351         if (!m_chid_current)
352                 eWarning("SCAN: the current channel's ID was not corrected - not adding channel.");
353         else
354                 addKnownGoodChannel(m_chid_current, m_ch_current);
355         
356         m_ch_scanned.push_back(m_ch_current);
357         nextChannel();
358 }
359
360 void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags)
361 {
362         m_flags = flags;
363         m_ch_toScan.clear();
364         m_ch_scanned.clear();
365         m_ch_unavailable.clear();
366         m_new_channels.clear();
367         m_new_services.clear();
368         m_ch_toScan.insert(m_ch_toScan.end(), known_transponders.begin(), known_transponders.end());
369         nextChannel();
370 }
371
372 void eDVBScan::insertInto(iDVBChannelList *db)
373 {
374         for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator 
375                         ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
376                 db->addChannelToList(ch->first, ch->second);
377         for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
378                 service(m_new_services.begin()); service != m_new_services.end(); ++service)
379         {
380                 ePtr<eDVBService> dvb_service;
381                 if (!db->getService(service->first, dvb_service))
382                         *dvb_service = *service->second;
383                 else
384                         db->addService(service->first, service->second);
385         }
386 }
387
388 RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt)
389 {
390         const ServiceDescriptionList &services = *sdt.getDescriptions();
391         SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
392         eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
393         
394                 /* save correct CHID for this channel if this is an ACTUAL_SDT */
395         if (sdt.getTableId() == TID_SDT_ACTUAL)
396                 m_chid_current = chid;
397         
398         for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
399         {
400                 SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
401
402                 eServiceReferenceDVB ref;
403                 ePtr<eDVBService> service = new eDVBService;
404                 
405                 ref.set(chid);
406                 ref.setServiceID((*s)->getServiceId());
407
408                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
409                                 desc != (*s)->getDescriptors()->end(); ++desc)
410                         if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
411                                 ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
412                 
413                 for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
414                                 desc != (*s)->getDescriptors()->end(); ++desc)
415                 {
416                         switch ((*desc)->getTag())
417                         {
418                         case SERVICE_DESCRIPTOR:
419                         {
420                                 ServiceDescriptor &d = (ServiceDescriptor&)**desc;
421                                 service->m_service_name = convertDVBUTF8(d.getServiceName());
422                                 service->genSortName();
423
424                                 service->m_provider_name = convertDVBUTF8(d.getServiceProviderName());
425                                 SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
426                                 break;
427                         }
428                         case CA_IDENTIFIER_DESCRIPTOR:
429                         {
430                                 CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
431                                 const CaSystemIdList &caids = *d.getCaSystemIds();
432                                 SCAN_eDebugNoNewLine("CA ");
433                                 for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
434                                 {
435                                         SCAN_eDebugNoNewLine("%04x ", *i);
436                                         service->m_ca.insert(*i);
437                                 }
438                                 SCAN_eDebug("");
439                                 break;
440                         }
441                         default:
442                                 SCAN_eDebug("descr<%x>", (*desc)->getTag());
443                                 break;
444                         }
445                 }
446                 
447                 m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));               
448         }
449         return 0;
450 }
451
452 RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
453 {
454         connection = new eConnection(this, m_event.connect(event));
455         return 0;
456 }
457
458 void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services)
459 {
460         transponders_done = m_ch_scanned.size() + m_ch_unavailable.size();
461         transponders_total = m_ch_toScan.size() + transponders_done;
462         services = m_new_services.size();
463 }