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