add hack for Kabel-BW 618Mhz Transponder.. (tsid is difference in PAT and
[enigma2.git] / lib / dvb / scan.cpp
index ba63ed9f3667e7b90f8cc679014eb31f4a9722f1..25be7005ae11e026e9a3c896a18976395608d528 100644 (file)
@@ -1,10 +1,9 @@
 #include <lib/dvb/idvb.h>
-#include <dvbsi++/service_description_section.h>
-#include <dvbsi++/network_information_section.h>
-#include <dvbsi++/bouquet_association_section.h>
 #include <dvbsi++/descriptor_tag.h>
 #include <dvbsi++/service_descriptor.h>
 #include <dvbsi++/satellite_delivery_system_descriptor.h>
+#include <dvbsi++/terrestrial_delivery_system_descriptor.h>
+#include <dvbsi++/cable_delivery_system_descriptor.h>
 #include <dvbsi++/ca_identifier_descriptor.h>
 #include <lib/dvb/specs.h>
 #include <lib/dvb/esection.h>
 #include <lib/base/estring.h>
 #include <errno.h>
 
-#define SCAN_eDebug(x...) eDebug(x)
-#define SCAN_eDebugNoNewLine(x...) eDebugNoNewLine(x)
+static bool scan_debug;
+#define SCAN_eDebug(x...) do { if (scan_debug) eDebug(x); } while(0)
+#define SCAN_eDebugNoNewLine(x...) do { if (scan_debug) eDebugNoNewLine(x); } while(0)
 
 DEFINE_REF(eDVBScan);
 
-eDVBScan::eDVBScan(iDVBChannel *channel): m_channel(channel)
+eDVBScan::eDVBScan(iDVBChannel *channel, bool usePAT, bool debug)
+       :m_channel(channel), m_channel_state(iDVBChannel::state_idle)
+       ,m_ready(0), m_ready_all(usePAT ? (readySDT|readyPAT) : readySDT)
+       ,m_flags(0), m_usePAT(usePAT)
 {
+       scan_debug=debug;
        if (m_channel->getDemux(m_demux))
                SCAN_eDebug("scan: failed to allocate demux!");
        m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
@@ -80,10 +84,10 @@ RESULT eDVBScan::nextChannel()
 {
        ePtr<iDVBFrontend> fe;
 
-       m_SDT = 0; m_BAT = 0; m_NIT = 0;
+       m_SDT = 0; m_PAT = 0; m_BAT = 0; m_NIT = 0;
 
        m_ready = 0;
-       
+
                /* check what we need */
        m_ready_all = readySDT;
        
@@ -92,13 +96,16 @@ RESULT eDVBScan::nextChannel()
        
        if (m_flags & scanSearchBAT)
                m_ready_all |= readyBAT;
-       
+
+       if (m_usePAT)
+               m_ready_all |= readyPAT;
+
        if (m_ch_toScan.empty())
        {
-               eDebug("no channels left to scan.");
-               eDebug("%d channels scanned, %d were unavailable.", 
+               SCAN_eDebug("no channels left to scan.");
+               SCAN_eDebug("%d channels scanned, %d were unavailable.", 
                                m_ch_scanned.size(), m_ch_unavailable.size());
-               eDebug("%d channels in database.", m_new_channels.size());
+               SCAN_eDebug("%d channels in database.", m_new_channels.size());
                m_event(evtFinish);
                return -ENOENT;
        }
@@ -113,63 +120,89 @@ RESULT eDVBScan::nextChannel()
                return -ENOTSUP;
        }
 
-       int fetype;
-       fe->getFrontendType(fetype);
-       if ( fetype == iDVBFrontend::feSatellite)
-       {
-               eDVBFrontendParametersSatellite p;
-               m_ch_current->getDVBS(p);
-               m_chid_current = eDVBChannelID(p.orbital_position << 16, -1, -1);
-       }
-       else
-               m_chid_current = eDVBChannelID();
+       m_chid_current = eDVBChannelID();
 
        m_channel_state = iDVBChannel::state_idle;
+
        if (fe->tune(*m_ch_current))
-       {
                return nextChannel();
-               m_event(evtFail);
-               return -EINVAL;
-       }
-               
+
        m_event(evtUpdate);
        return 0;
 }
 
 RESULT eDVBScan::startFilter()
 {
+       bool startSDT=true;
        assert(m_demux);
-       
+
                        /* only start required filters filter */
-       
-       m_SDT = 0;
 
-       if (m_ready_all & readySDT)
+       if (m_ready_all & readyPAT)
+               startSDT = m_ready & readyPAT;
+
+       m_SDT = 0;
+       if (startSDT && (m_ready_all & readySDT))
        {
                m_SDT = new eTable<ServiceDescriptionSection>();
-               if (m_SDT->start(m_demux, eDVBSDTSpec()))
+               int tsid=-1;
+               if (m_ready & readyPAT && m_ready & validPAT)
+               {
+                       std::vector<ProgramAssociationSection*>::const_iterator i =
+                               m_PAT->getSections().begin();
+                       assert(i != m_PAT->getSections().end());
+                       tsid = (*i)->getTableIdExtension(); // in PAT this is the transport stream id
+
+                       // KabelBW HACK ... on 618 Mhz the transport stream id in PAT and SDT is different
+                       {
+                               int type;
+                               m_ch_current->getSystem(type);
+                               if (type == iDVBFrontend::feCable)
+                               {
+                                       eDVBFrontendParametersCable parm;
+                                       m_ch_current->getDVBC(parm);
+                                       if (tsid == 0x00d7 & abs(parm.frequency-618000) < 2000)
+                                               tsid = -1;
+                               }
+                       }
+               }
+               if (tsid == -1 && m_SDT->start(m_demux, eDVBSDTSpec()))
+                       return -1;
+               else if (m_SDT->start(m_demux, eDVBSDTSpec(tsid, true)))
                        return -1;
                CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
        }
 
-       m_NIT = 0;
-       if (m_ready_all & readyNIT)
+       if (!(m_ready & readyPAT))
        {
-               m_NIT = new eTable<NetworkInformationSection>();
-               if (m_NIT->start(m_demux, eDVBNITSpec()))
-                       return -1;
-               CONNECT(m_NIT->tableReady, eDVBScan::NITready);
-       }
+               m_PAT = 0;
+               if (m_ready_all & readyPAT)
+               {
+                       m_PAT = new eTable<ProgramAssociationSection>();
+                       if (m_PAT->start(m_demux, eDVBPATSpec()))
+                               return -1;
+                       CONNECT(m_PAT->tableReady, eDVBScan::PATready);
+               }
 
-       m_BAT = 0;
-       if (m_ready_all & readyBAT)
-       {
-               m_BAT = new eTable<BouquetAssociationSection>();
-               if (m_BAT->start(m_demux, eDVBBATSpec()))
-                       return -1;
-               CONNECT(m_BAT->tableReady, eDVBScan::BATready);
+               m_NIT = 0;
+               if (m_ready_all & readyNIT)
+               {
+                       m_NIT = new eTable<NetworkInformationSection>();
+                       if (m_NIT->start(m_demux, eDVBNITSpec()))
+                               return -1;
+                       CONNECT(m_NIT->tableReady, eDVBScan::NITready);
+               }
+
+               m_BAT = 0;
+               if (m_ready_all & readyBAT)
+               {
+                       m_BAT = new eTable<BouquetAssociationSection>();
+                       if (m_BAT->start(m_demux, eDVBBATSpec()))
+                               return -1;
+                       CONNECT(m_BAT->tableReady, eDVBScan::BATready);
+               }
        }
-       
+
        return 0;
 }
 
@@ -200,6 +233,15 @@ void eDVBScan::BATready(int err)
        channelDone();
 }
 
+void eDVBScan::PATready(int err)
+{
+       SCAN_eDebug("got pat");
+       m_ready |= readyPAT;
+       if (!err)
+               m_ready |= validPAT;
+       startFilter(); // for starting the SDT filter
+}
+
 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
 {
                /* add it to the list of known channels. */
@@ -210,34 +252,99 @@ void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParame
 void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
 {
                /* check if we don't already have that channel ... */
-               
+
+       int type;
+       feparm->getSystem(type);
+
+       switch(type)
+       {
+       case iDVBFrontend::feSatellite:
+       {
+               eDVBFrontendParametersSatellite parm;
+               feparm->getDVBS(parm);
+               eDebug("try to add %d %d %d %d %d %d",
+                       parm.orbital_position, parm.frequency, parm.symbol_rate, parm.polarisation, parm.fec, parm.modulation);
+               break;
+       }
+       case iDVBFrontend::feCable:
+       {
+               eDVBFrontendParametersCable parm;
+               feparm->getDVBC(parm);
+               eDebug("try to add %d %d %d %d",
+                       parm.frequency, parm.symbol_rate, parm.modulation, parm.fec_inner);
+               break;
+       }
+       case iDVBFrontend::feTerrestrial:
+       {
+               eDVBFrontendParametersTerrestrial parm;
+               feparm->getDVBT(parm);
+               eDebug("try to add %d %d %d %d %d %d %d %d",
+                       parm.frequency, parm.modulation, parm.transmission_mode, parm.hierarchy,
+                       parm.guard_interval, parm.code_rate_LP, parm.code_rate_HP, parm.bandwidth);
+               break;
+       }
+       }
+
+       int found_count=0;
                /* ... in the list of channels to scan */
-       for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
+       for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
+       {
                if (sameChannel(*i, feparm))
-                       return;
+               {
+                       if (!found_count)
+                       {
+                               *i = feparm;  // update
+                               eDebug("update");
+                       }
+                       else
+                       {
+                               eDebug("remove dupe");
+                               m_ch_toScan.erase(i++);
+                               continue;
+                       }
+                       ++found_count;
+               }
+               ++i;
+       }
+
+       if (found_count > 0)
+       {
+               eDebug("already in todo list");
+               return;
+       }
 
                /* ... in the list of successfully scanned channels */
        for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
                if (sameChannel(*i, feparm))
+               {
+                       eDebug("successfully scanned");
                        return;
-               
+               }
+
                /* ... in the list of unavailable channels */
        for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
-               if (sameChannel(*i, feparm))
+               if (sameChannel(*i, feparm, true))
+               {
+                       eDebug("scanned but not available");
                        return;
+               }
 
                /* ... on the current channel */
        if (sameChannel(m_ch_current, feparm))
+       {
+               eDebug("is current");
                return;
+       }
 
+       eDebug("really add");
                /* otherwise, add it to the todo list. */
        m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :)
 }
 
-int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
+int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2, bool exact) const
 {
        int diff;
-       if (ch1->calculateDifference(ch2, diff))
+       if (ch1->calculateDifference(ch2, diff, exact))
                return 0;
        if (diff < 4000) // more than 4mhz difference?
                return 1;
@@ -249,6 +356,11 @@ void eDVBScan::channelDone()
        if (m_ready & validSDT)
        {
                unsigned long hash = 0;
+
+               // m_ch_current is not set, when eDVBScan is just used for a SDT update
+               if (!m_ch_current)
+                       m_channel->getCurrentFrontendParameters(m_ch_current);
+
                m_ch_current->getHash(hash);
                
                eDVBNamespace dvbnamespace = buildNamespace(
@@ -265,7 +377,15 @@ void eDVBScan::channelDone()
        
        if (m_ready & validNIT)
        {
+               int system;
+               std::list<ePtr<iDVBFrontendParameters> > m_ch_toScan_backup;
+               m_ch_current->getSystem(system);
                SCAN_eDebug("dumping NIT");
+               if (m_flags & clearToScanOnFirstNIT)
+               {
+                       m_ch_toScan_backup = m_ch_toScan;
+                       m_ch_toScan.clear();
+               }
                std::vector<NetworkInformationSection*>::const_iterator i;
                for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
                {
@@ -285,39 +405,79 @@ void eDVBScan::channelDone()
                                {
                                        switch ((*desc)->getTag())
                                        {
-//                                     case SERVICE_LIST_DESCRIPTOR:
+                                       case CABLE_DELIVERY_SYSTEM_DESCRIPTOR:
+                                       {
+                                               if (system != iDVBFrontend::feCable)
+                                                       break; // when current locked transponder is no cable transponder ignore this descriptor
+                                               CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc;
+                                               ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
+                                               eDVBFrontendParametersCable cable;
+                                               cable.set(d);
+                                               feparm->setDVBC(cable);
+
+                                               unsigned long hash=0;
+                                               feparm->getHash(hash);
+                                               eDVBNamespace ns = buildNamespace(onid, tsid, hash);
+
+                                               addChannelToScan(
+                                                       eDVBChannelID(ns, tsid, onid),
+                                                       feparm);
+                                               break;
+                                       }
+                                       case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR:
+                                       {
+                                               if (system != iDVBFrontend::feTerrestrial)
+                                                       break; // when current locked transponder is no terrestrial transponder ignore this descriptor
+                                               TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc;
+                                               ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
+                                               eDVBFrontendParametersTerrestrial terr;
+                                               terr.set(d);
+                                               feparm->setDVBT(terr);
+
+                                               unsigned long hash=0;
+                                               feparm->getHash(hash);
+                                               eDVBNamespace ns = buildNamespace(onid, tsid, hash);
+
+                                               addChannelToScan(
+                                                       eDVBChannelID(ns, tsid, onid),
+                                                       feparm);
+                                               break;
+                                       }
                                        case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
                                        {
+                                               if (system != iDVBFrontend::feSatellite)
+                                                       break; // when current locked transponder is no satellite transponder ignore this descriptor
+
                                                SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
-                                               SCAN_eDebug("%d kHz, %d%d%d.%d%c %s MOD:%d %d symb/s, fec %d", 
-                                                               d.getFrequency(), 
-                                                               (d.getOrbitalPosition()>>12)&0xF,
-                                                               (d.getOrbitalPosition()>>8)&0xF,
-                                                               (d.getOrbitalPosition()>>4)&0xF,
-                                                               d.getOrbitalPosition()&0xF, d.getWestEastFlag()?'E':'W',
-                                                               d.getPolarization() ? "hor" : "vert",
-                                                               d.getModulation(), d.getSymbolRate(), d.getFecInner());
-                                               
-                                                       /* some sanity checking: below 100MHz is invalid */
                                                if (d.getFrequency() < 10000)
                                                        break;
                                                
                                                ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
                                                eDVBFrontendParametersSatellite sat;
                                                sat.set(d);
+
+                                               eDVBFrontendParametersSatellite p;
+                                               m_ch_current->getDVBS(p);
+
+                                               if ( abs(p.orbital_position - sat.orbital_position) < 5 )
+                                                       sat.orbital_position = p.orbital_position;
+
+                                               if ( abs(abs(3600 - p.orbital_position) - sat.orbital_position) < 5 )
+                                               {
+                                                       eDebug("found transponder with incorrect west/east flag ... correct this");
+                                                       sat.orbital_position = p.orbital_position;
+                                               }
+
                                                feparm->setDVBS(sat);
-                                               unsigned long hash=0;
-                                               feparm->getHash(hash);
-                                               
-                                               eDVBNamespace ns = buildNamespace(onid, tsid, hash);
-                                               
-                                               if ( m_chid_current.dvbnamespace.get() != -1 &&
-                                                       ((ns.get() ^ m_chid_current.dvbnamespace.get()) & 0xFFFF0000))
-                                                       eDebug("dropping this transponder, it's on another satellite.");
+
+                                               if ( p.orbital_position != sat.orbital_position)
+                                                       SCAN_eDebug("dropping this transponder, it's on another satellite.");
                                                else
                                                {
+                                                       unsigned long hash=0;
+                                                       feparm->getHash(hash);
                                                        addChannelToScan(
-                                                                       eDVBChannelID(ns, tsid, onid),
+                                                                       eDVBChannelID(buildNamespace(onid, tsid, hash), tsid, onid),
                                                                        feparm);
                                                }
                                                break;
@@ -327,9 +487,25 @@ void eDVBScan::channelDone()
                                                break;
                                        }
                                }
-                               
                        }
+                       
                }
+
+                       /* a pitfall is to have the clearToScanOnFirstNIT-flag set, and having channels which have
+                          no or invalid NIT. this code will not erase the toScan list unless at least one valid entry
+                          has been found.
+
+                          This is not a perfect solution, as the channel could contain a partial NIT. Life's bad.
+                       */
+               if (m_flags & clearToScanOnFirstNIT)
+               {
+                       if (m_ch_toScan.empty())
+                       {
+                               eWarning("clearToScanOnFirstNIT was set, but NIT is invalid. Refusing to stop scan.");
+                               m_ch_toScan = m_ch_toScan_backup;
+                       } else
+                               m_flags &= ~clearToScanOnFirstNIT;
+               }
                m_ready &= ~validNIT;
        }
        
@@ -364,6 +540,18 @@ void eDVBScan::channelDone()
                addKnownGoodChannel(m_chid_current, m_ch_current);
        
        m_ch_scanned.push_back(m_ch_current);
+       
+       for (std::list<ePtr<iDVBFrontendParameters> >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();)
+       {
+               if (sameChannel(*i, m_ch_current))
+               {
+                       eDebug("remove dupe 2");
+                       m_ch_toScan.erase(i++);
+                       continue;
+               }
+               ++i;
+       }
+       
        nextChannel();
 }
 
@@ -375,13 +563,14 @@ void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transpon
        m_ch_unavailable.clear();
        m_new_channels.clear();
        m_new_services.clear();
+       m_last_service = m_new_services.end();
 
        for (eSmartPtrList<iDVBFrontendParameters>::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i)
        {
                bool exist=false;
                for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii)
                {
-                       if (sameChannel(*i, *ii))
+                       if (sameChannel(*i, *ii, true))
                        {
                                exist=true;
                                break;
@@ -394,8 +583,89 @@ void eDVBScan::start(const eSmartPtrList<iDVBFrontendParameters> &known_transpon
        nextChannel();
 }
 
-void eDVBScan::insertInto(iDVBChannelList *db)
+void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
 {
+       if (m_flags & scanRemoveServices)
+       {
+               bool clearTerrestrial=false;
+               bool clearCable=false;
+               std::set<unsigned int> scanned_sat_positions;
+               
+               std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
+               for (;it != m_ch_scanned.end(); ++it)
+               {
+                       int system;
+                       (*it)->getSystem(system);
+                       switch(system)
+                       {
+                               case iDVBFrontend::feSatellite:
+                               {
+                                       eDVBFrontendParametersSatellite sat_parm;
+                                       (*it)->getDVBS(sat_parm);
+                                       scanned_sat_positions.insert(sat_parm.orbital_position);
+                                       break;
+                               }
+                               case iDVBFrontend::feTerrestrial:
+                               {
+                                       clearTerrestrial=true;
+                                       break;
+                               }
+                               case iDVBFrontend::feCable:
+                               {
+                                       clearCable=true;
+                                       break;
+                               }
+                       }
+               }
+
+               for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it)
+               {
+                       int system;
+                       (*it)->getSystem(system);
+                       switch(system)
+                       {
+                               case iDVBFrontend::feSatellite:
+                               {
+                                       eDVBFrontendParametersSatellite sat_parm;
+                                       (*it)->getDVBS(sat_parm);
+                                       scanned_sat_positions.insert(sat_parm.orbital_position);
+                                       break;
+                               }
+                               case iDVBFrontend::feTerrestrial:
+                               {
+                                       clearTerrestrial=true;
+                                       break;
+                               }
+                               case iDVBFrontend::feCable:
+                               {
+                                       clearCable=true;
+                                       break;
+                               }
+                       }
+               }
+
+               if (clearTerrestrial)
+               {
+                       eDVBChannelID chid;
+                       chid.dvbnamespace=0xEEEE0000;
+                       db->removeServices(chid);
+               }
+               if (clearCable)
+               {
+                       eDVBChannelID chid;
+                       chid.dvbnamespace=0xFFFF0000;
+                       db->removeServices(chid);
+               }
+               for (std::set<unsigned int>::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x)
+               {
+                       eDVBChannelID chid;
+                       if (m_flags & scanDontRemoveFeeds)
+                               chid.dvbnamespace = eDVBNamespace((*x)<<16);
+//                     eDebug("remove %d %08x", *x, chid.dvbnamespace.get());
+                       db->removeServices(chid, *x);
+               }
+       }
+
        for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator 
                        ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
                db->addChannelToList(ch->first, ch->second);
@@ -404,9 +674,26 @@ void eDVBScan::insertInto(iDVBChannelList *db)
        {
                ePtr<eDVBService> dvb_service;
                if (!db->getService(service->first, dvb_service))
-                       *dvb_service = *service->second;
+               {
+                       if (dvb_service->m_flags & eDVBService::dxNoSDT)
+                               continue;
+                       if (!(dvb_service->m_flags & eDVBService::dxHoldName))
+                       {
+                               dvb_service->m_service_name = service->second->m_service_name;
+                               dvb_service->m_service_name_sort = service->second->m_service_name_sort;
+                       }
+                       dvb_service->m_provider_name = service->second->m_provider_name;
+                       if (service->second->m_ca.size())
+                               dvb_service->m_ca = service->second->m_ca;
+                       if (!dontRemoveOldFlags) // do not remove new found flags when not wished
+                               dvb_service->m_flags &= ~eDVBService::dxNewFound;
+               }
                else
+               {
                        db->addService(service->first, service->second);
+                       if (!(m_flags & scanRemoveServices))
+                               service->second->m_flags |= eDVBService::dxNewFound;
+               }
        }
 }
 
@@ -416,10 +703,9 @@ RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescription
        SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId());
        eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
        
-               /* save correct CHID for this channel if this is an ACTUAL_SDT */
-       if (sdt.getTableId() == TID_SDT_ACTUAL)
-               m_chid_current = chid;
-       
+       /* save correct CHID for this channel */
+       m_chid_current = chid;
+
        for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
        {
                SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
@@ -458,7 +744,7 @@ RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescription
                                for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
                                {
                                        SCAN_eDebugNoNewLine("%04x ", *i);
-                                       service->m_ca.insert(*i);
+                                       service->m_ca.push_front(*i);
                                }
                                SCAN_eDebug("");
                                break;
@@ -469,7 +755,13 @@ RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescription
                        }
                }
                
-               m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));               
+               std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
+               
+               if (i.second)
+               {
+                       m_last_service = i.first;
+                       m_event(evtNewService);
+               }
        }
        return 0;
 }
@@ -486,3 +778,30 @@ void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &se
        transponders_total = m_ch_toScan.size() + transponders_done;
        services = m_new_services.size();
 }
+
+void eDVBScan::getLastServiceName(std::string &last_service_name)
+{
+       if (m_last_service == m_new_services.end())
+               last_service_name = "";
+       else
+               last_service_name = m_last_service->second->m_service_name;
+}
+
+RESULT eDVBScan::getFrontend(ePtr<iDVBFrontend> &fe)
+{
+       if (m_channel)
+               return m_channel->getFrontend(fe);
+       fe = 0;
+       return -1;
+}
+
+RESULT eDVBScan::getCurrentTransponder(ePtr<iDVBFrontendParameters> &tp)
+{
+       if (m_ch_current)
+       {
+               tp = m_ch_current;
+               return 0;
+       }
+       tp = 0;
+       return -1;
+}