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