performance fix
[enigma2.git] / lib / dvb / epgcache.cpp
index 41635b03ebdf2c909d3f25c299378570c691cd53..7a1f78ddebc68df7d18979833684d5b62dcf433f 100644 (file)
@@ -6,7 +6,7 @@
 #include <time.h>
 #include <unistd.h>  // for usleep
 #include <sys/vfs.h> // for statfs
-#include <libmd5sum.h>
+// #include <libmd5sum.h>
 #include <lib/base/eerror.h>
 
 int eventData::CacheSize=0;
@@ -14,24 +14,26 @@ int eventData::CacheSize=0;
 eEPGCache* eEPGCache::instance;
 pthread_mutex_t eEPGCache::cache_lock=
        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+pthread_mutex_t eEPGCache::channel_map_lock=
+       PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 
 DEFINE_REF(eEPGCache)
 
 eEPGCache::eEPGCache()
-       :messages(this,1), back_messages(this,1) ,paused(0)
-       ,CleanTimer(this), zapTimer(this), abortTimer(this)
+       :messages(this,1), cleanTimer(this)//, paused(0)
 {
        eDebug("[EPGC] Initialized EPGCache");
-       isRunning=0;
 
        CONNECT(messages.recv_msg, eEPGCache::gotMessage);
-       CONNECT(back_messages.recv_msg, eEPGCache::gotBackMessage);
-//     CONNECT(eDVB::getInstance()->switchedService, eEPGCache::enterService);
-//     CONNECT(eDVB::getInstance()->leaveService, eEPGCache::leaveService);
        CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated);
-       CONNECT(zapTimer.timeout, eEPGCache::startEPG);
-       CONNECT(CleanTimer.timeout, eEPGCache::cleanLoop);
-       CONNECT(abortTimer.timeout, eEPGCache::abortNonAvail);
+       CONNECT(cleanTimer.timeout, eEPGCache::cleanLoop);
+
+       ePtr<eDVBResourceManager> res_mgr;
+       eDVBResourceManager::getInstance(res_mgr);
+       if (!res_mgr)
+               eDebug("[eEPGCache] no resource manager !!!!!!!");
+       else
+               res_mgr->connectChannelAdded(slot(*this,&eEPGCache::DVBChannelAdded), m_chanAddedConn);
        instance=this;
 }
 
@@ -46,16 +48,116 @@ void eEPGCache::timeUpdated()
                messages.send(Message(Message::timeChanged));
 }
 
-int eEPGCache::sectionRead(const __u8 *data, int source)
+void eEPGCache::DVBChannelAdded(eDVBChannel *chan)
+{
+       if ( chan )
+       {
+               eDebug("[eEPGCache] add channel %p", chan);
+               channel_data *data = new channel_data(this);
+               data->channel = chan;
+               singleLock s(channel_map_lock);
+               m_knownChannels.insert( std::pair<iDVBChannel*, channel_data* >(chan, data) );
+               chan->connectStateChange(slot(*this, &eEPGCache::DVBChannelStateChanged), data->m_stateChangedConn);
+       }
+}
+
+void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
+{
+       singleLock s(channel_map_lock);
+       channelMapIterator it =
+               m_knownChannels.find(chan);
+       if ( it == m_knownChannels.end() )
+               eDebug("[eEPGCache] will start non existing channel %p !!!", chan);
+       else
+       {
+               channel_data &data = *it->second;
+               ePtr<eDVBResourceManager> res_mgr;
+               if ( eDVBResourceManager::getInstance( res_mgr ) )
+                       eDebug("[eEPGCache] no res manager!!");
+               else
+               {
+                       ePtr<iDVBDemux> demux;
+                       if ( data.channel->getDemux(demux) )
+                       {
+                               eDebug("[eEPGCache] no demux!!");
+                               return;
+                       }
+                       else
+                       {
+                               RESULT res = demux->createSectionReader( this, data.m_NowNextReader );
+                               if ( res )
+                               {
+                                       eDebug("[eEPGCache] couldnt initialize nownext reader!!");
+                                       return;
+                               }
+                               data.m_NowNextReader->connectRead(slot(data, &eEPGCache::channel_data::readData), data.m_NowNextConn);
+                               res = demux->createSectionReader( this, data.m_ScheduleReader );
+                               if ( res )
+                               {
+                                       eDebug("[eEPGCache] couldnt initialize schedule reader!!");
+                                       return;
+                               }
+                               data.m_ScheduleReader->connectRead(slot(data, &eEPGCache::channel_data::readData), data.m_ScheduleConn);
+                               res = demux->createSectionReader( this, data.m_ScheduleOtherReader );
+                               if ( res )
+                               {
+                                       eDebug("[eEPGCache] couldnt initialize schedule other reader!!");
+                                       return;
+                               }
+                               data.m_ScheduleOtherReader->connectRead(slot(data, &eEPGCache::channel_data::readData), data.m_ScheduleOtherConn);
+                               messages.send(Message(Message::startChannel, chan));
+                               // -> gotMessage -> changedService
+                       }
+               }
+       }
+}
+
+void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan)
+{
+       channelMapIterator it =
+               m_knownChannels.find(chan);
+       if ( it != m_knownChannels.end() )
+       {
+               int state=0;
+               chan->getState(state);
+               switch (state)
+               {
+                       case iDVBChannel::state_idle:
+                               break;
+                       case iDVBChannel::state_tuning:
+                               break;
+                       case iDVBChannel::state_unavailable:
+                               break;
+                       case iDVBChannel::state_ok:
+                       {
+                               eDebug("[eEPGCache] channel %p running", chan);
+                               DVBChannelRunning(chan);
+                               break;
+                       }
+                       case iDVBChannel::state_release:
+                       {
+                               eDebug("[eEPGCache] remove channel %p", chan);
+                               messages.send(Message(Message::leaveChannel, chan));
+                               while(!it->second->can_delete)
+                                       usleep(1000);
+                               delete it->second;
+                               m_knownChannels.erase(it);
+                               // -> gotMessage -> abortEPG
+                               break;
+                       }
+               }
+       }
+}
+
+void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
 {
        eit_t *eit = (eit_t*) data;
 
        int len=HILO(eit->section_length)-1;//+3-4;
        int ptr=EIT_SIZE;
        if ( ptr >= len )
-               return 0;
+               return;
 
-       //
        // This fixed the EPG on the Multichoice irdeto systems
        // the EIT packet is non-compliant.. their EIT packet stinks
        if ( data[ptr-1] < 0x40 )
@@ -67,26 +169,12 @@ int eEPGCache::sectionRead(const __u8 *data, int source)
        int duration;
 
        time_t TM = parseDVBtime( eit_event->start_time_1, eit_event->start_time_2,     eit_event->start_time_3, eit_event->start_time_4, eit_event->start_time_5);
-// FIXME !!! TIME CORRECTION !
        time_t now = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
 
        if ( TM != 3599 && TM > -1)
-       {
-               switch(source)
-               {
-               case NOWNEXT:
-                       haveData |= 2;
-                       break;
-               case SCHEDULE:
-                       haveData |= 1;
-                       break;
-               case SCHEDULE_OTHER:
-                       haveData |= 4;
-                       break;
-               }
-       }
+               channel->haveData |= source;
 
-       Lock();
+       singleLock s(cache_lock);
        // hier wird immer eine eventMap zurück gegeben.. entweder eine vorhandene..
        // oder eine durch [] erzeugte
        std::pair<eventMap,timeMap> &servicemap = eventDB[service];
@@ -120,7 +208,7 @@ int eEPGCache::sectionRead(const __u8 *data, int source)
                        int ev_erase_count = 0;
                        int tm_erase_count = 0;
 
-// search in eventmap
+                       // search in eventmap
                        eventMap::iterator ev_it =
                                servicemap.first.find(event_id);
 
@@ -129,7 +217,8 @@ int eEPGCache::sectionRead(const __u8 *data, int source)
                        {
                                if ( source > ev_it->second->type )  // update needed ?
                                        goto next; // when not.. the skip this entry
-// search this event in timemap
+
+                               // search this event in timemap
                                timeMap::iterator tm_it_tmp = 
                                        servicemap.second.find(ev_it->second->getStartTime());
 
@@ -154,21 +243,20 @@ int eEPGCache::sectionRead(const __u8 *data, int source)
                                }
                        }
 
-// search in timemap, for check of a case if new time has coincided with time of other event 
-// or event was is not found in eventmap
+                       // search in timemap, for check of a case if new time has coincided with time of other event 
+                       // or event was is not found in eventmap
                        timeMap::iterator tm_it =
                                servicemap.second.find(TM);
 
                        if ( tm_it != servicemap.second.end() )
                        {
-
-// i think, if event is not found on eventmap, but found on timemap updating nevertheless demands
+                               // i think, if event is not found on eventmap, but found on timemap updating nevertheless demands
 #if 0
                                if ( source > tm_it->second->type && tm_erase_count == 0 ) // update needed ?
                                        goto next; // when not.. the skip this entry
 #endif
 
-// search this time in eventmap
+                               // search this time in eventmap
                                eventMap::iterator ev_it_tmp = 
                                        servicemap.first.find(tm_it->second->getEventID());
 
@@ -250,8 +338,8 @@ next:
                        i=0;
                        for (timeMap::iterator it(servicemap.second.begin())
                                ; it != servicemap.second.end(); ++it )
-                       fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
-                               i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
+                                       fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
+                                               i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
                        fclose(f);
 
                        eFatal("(1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d", 
@@ -262,68 +350,12 @@ next:
                ptr += eit_event_size;
                eit_event=(eit_event_struct*)(((__u8*)eit_event)+eit_event_size);
        }
-
-       tmpMap::iterator it = temp.find( service );
-       if ( it != temp.end() )
-       {
-               if ( source > it->second.second )
-               {
-                       it->second.first=now;
-                       it->second.second=source;
-               }
-       }
-       else
-               temp[service] = std::pair< time_t, int> (now, source);
-
-       Unlock();
-
-       return 0;
-}
-
-bool eEPGCache::finishEPG()
-{
-       if (!isRunning)  // epg ready
-       {
-               eDebug("[EPGC] stop caching events");
-               zapTimer.start(UPDATE_INTERVAL, 1);
-               eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000);
-
-               singleLock l(cache_lock);
-               tmpMap::iterator It = temp.begin();
-               abortTimer.stop();
-
-               while (It != temp.end())
-               {
-//                     eDebug("sid = %02x, onid = %02x, type %d", It->first.sid, It->first.onid, It->second.second );
-                       if ( It->second.second == SCHEDULE
-                               || ( It->second.second == NOWNEXT && !(haveData&1) ) 
-                               )
-                       {
-//                             eDebug("ADD to last updated Map");
-                               serviceLastUpdated[It->first]=It->second.first;
-                       }
-                       if ( eventDB.find( It->first ) == eventDB.end() )
-                       {
-//                             eDebug("REMOVE from update Map");
-                               temp.erase(It++);
-                       }
-                       else
-                               It++;
-               }
-               if (!eventDB[current_service].first.empty())
-                       /*emit*/ EPGAvail(1);
-
-               /*emit*/ EPGUpdated();
-
-               return true;
-       }
-       return false;
 }
 
 void eEPGCache::flushEPG(const uniqueEPGKey & s)
 {
        eDebug("[EPGC] flushEPG %d", (int)(bool)s);
-       Lock();
+       singleLock l(cache_lock);
        if (s)  // clear only this service
        {
                eventCache::iterator it = eventDB.find(s);
@@ -336,10 +368,8 @@ void eEPGCache::flushEPG(const uniqueEPGKey & s)
                                delete i->second;
                        evMap.clear();
                        eventDB.erase(it);
-                       updateMap::iterator u = serviceLastUpdated.find(s);
-                       if ( u != serviceLastUpdated.end() )
-                               serviceLastUpdated.erase(u);
-                       startEPG();
+
+                       // TODO .. search corresponding channel for removed service and remove this channel from lastupdated map
                }
        }
        else // clear complete EPG Cache
@@ -354,24 +384,19 @@ void eEPGCache::flushEPG(const uniqueEPGKey & s)
                        evMap.clear();
                        tmMap.clear();
                }
-               serviceLastUpdated.clear();
                eventDB.clear();
-               startEPG();
+               channelLastUpdated.clear();
+               singleLock m(channel_map_lock);
+               for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
+                       it->second->startEPG();
        }
        eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
-       Unlock();
 }
 
 void eEPGCache::cleanLoop()
 {
        singleLock s(cache_lock);
-       if ( isRunning )
-       {
-               CleanTimer.start(5000,true);
-               eDebug("[EPGC] schedule cleanloop");
-               return;
-       }
-       if (!eventDB.empty() && !paused )
+       if (!eventDB.empty())
        {
                eDebug("[EPGC] start cleanloop");
                const eit_event_struct* cur_event;
@@ -403,51 +428,25 @@ void eEPGCache::cleanLoop()
                                        delete It->second;
                                        DBIt->second.second.erase(It++);
 //                                     eDebug("[EPGC] delete old event (timeMap)");
-
-                                       // add this (changed) service to temp map...
-                                       if ( temp.find(DBIt->first) == temp.end() )
-                                               temp[DBIt->first]=std::pair<time_t, int>(now, NOWNEXT);
                                }
                                else
                                        ++It;
                        }
-                       if ( DBIt->second.second.size() < 2 )  
-                       // less than two events for this service in cache.. 
-                       {
-                               updateMap::iterator u = serviceLastUpdated.find(DBIt->first);
-                               if ( u != serviceLastUpdated.end() )
-                               {
-                                       // remove from lastupdated map.. 
-                                       serviceLastUpdated.erase(u);
-                                       // current service?
-                                       if ( DBIt->first == current_service )
-                                       {
-                                       // immediate .. after leave cleanloop 
-                                       // update epgdata for this service
-                                               zapTimer.start(0,true);
-                                       }
-                               }
-                       }
                }
-
-               if (temp.size())
-                       /*emit*/ EPGUpdated();
-
                eDebug("[EPGC] stop cleanloop");
                eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
        }
-       CleanTimer.start(CLEAN_INTERVAL,true);
+       cleanTimer.start(CLEAN_INTERVAL,true);
 }
 
 eEPGCache::~eEPGCache()
 {
        messages.send(Message::quit);
        kill(); // waiting for thread shutdown
-       Lock();
+       singleLock s(cache_lock);
        for (eventCache::iterator evIt = eventDB.begin(); evIt != eventDB.end(); evIt++)
                for (eventMap::iterator It = evIt->second.first.begin(); It != evIt->second.first.end(); It++)
                        delete It->second;
-       Unlock();
 }
 
 Event *eEPGCache::lookupEvent(const eServiceReferenceDVB &service, int event_id, bool plain)
@@ -526,250 +525,6 @@ Event *eEPGCache::lookupEvent(const eServiceReferenceDVB &service, time_t t, boo
        return 0;
 }
 
-void eEPGCache::pauseEPG()
-{
-       if (!paused)
-       {
-               abortEPG();
-               eDebug("[EPGC] paused]");
-               paused=1;
-       }
-}
-
-void eEPGCache::restartEPG()
-{
-       if (paused)
-       {
-               isRunning=0;
-               eDebug("[EPGC] restarted");
-               paused--;
-               if (paused)
-               {
-                       paused = 0;
-                       startEPG();   // updateEPG
-               }
-               cleanLoop();
-       }
-}
-
-void eEPGCache::startEPG()
-{
-       if (paused)  // called from the updateTimer during pause...
-       {
-               paused++;
-               return;
-       }
-       if (eDVBLocalTimeHandler::getInstance()->ready())
-       {
-               Lock();
-               temp.clear();
-               Unlock();
-               eDebug("[EPGC] start caching events");
-               state=0;
-               haveData=0;
-
-               eDVBSectionFilterMask mask;
-               memset(&mask, 0, sizeof(mask));
-               mask.pid = 0x12;
-               mask.flags = eDVBSectionFilterMask::rfCRC;
-
-               mask.data[0] = 0x4E;
-               mask.mask[0] = 0xFE;
-               m_NowNextReader->start(mask);
-               isRunning |= 1;
-
-               mask.data[0] = 0x50;
-               mask.mask[0] = 0xF0;
-               m_ScheduleReader->start(mask);
-               isRunning |= 2;
-
-               mask.data[0] = 0x60;
-               mask.mask[0] = 0xF0;
-               m_ScheduleOtherReader->start(mask);
-               isRunning |= 4;
-
-               abortTimer.start(5000,true);
-       }
-       else
-       {
-               eDebug("[EPGC] wait for clock update");
-               zapTimer.start(1000, 1); // restart Timer
-       }
-}
-
-void eEPGCache::abortNonAvail()
-{
-       if (!state)
-       {
-               if ( !(haveData&2) && (isRunning&2) )
-               {
-                       eDebug("[EPGC] abort non avail nownext reading");
-                       isRunning &= ~2;
-                       if ( m_NowNextReader )
-                               m_NowNextReader->stop();
-               }
-               if ( !(haveData&1) && (isRunning&1) )
-               {
-                       eDebug("[EPGC] abort non avail schedule reading");
-                       isRunning &= ~1;
-                       m_ScheduleReader->stop();
-               }
-               if ( !(haveData&4) && (isRunning&4) )
-               {
-                       eDebug("[EPGC] abort non avail schedule_other reading");
-                       isRunning &= ~4;
-                       m_ScheduleOtherReader->stop();
-               }
-               abortTimer.start(20000, true);
-       }
-       ++state;
-}
-
-void eEPGCache::startCache(const eServiceReferenceDVB& ref)
-{
-       if ( m_currentChannel )
-       {
-               next_service = ref;
-               leaveChannel(m_currentChannel);
-               return;
-       }
-       eDVBChannelID chid;
-       ref.getChannelID( chid );
-       ePtr<eDVBResourceManager> res_mgr;
-       if ( eDVBResourceManager::getInstance( res_mgr ) )
-               eDebug("[eEPGCache] no res manager!!");
-       else
-       {
-               ePtr<iDVBDemux> demux;
-               res_mgr->allocateChannel(chid, m_currentChannel);
-               if ( m_currentChannel->getDemux(demux) )
-               {
-                       eDebug("[eEPGCache] no demux!!");
-                       goto error4;
-               }
-               else
-               {
-                       RESULT res;
-                       m_NowNextReader = new eDVBSectionReader( demux, this, res );
-                       if ( res )
-                       {
-                               eDebug("[eEPGCache] couldnt initialize nownext reader!!");
-                               goto error3;
-                       }
-                       m_NowNextReader->connectRead(slot(*this, &eEPGCache::readNowNextData), m_NowNextConn);
-                       m_ScheduleReader = new eDVBSectionReader( demux, this, res );
-                       if ( res )
-                       {
-                               eDebug("[eEPGCache] couldnt initialize schedule reader!!");
-                               goto error2;
-                       }
-                       m_ScheduleReader->connectRead(slot(*this, &eEPGCache::readScheduleData), m_ScheduleConn);
-                       m_ScheduleOtherReader = new eDVBSectionReader( demux, this, res );
-                       if ( res )
-                       {
-                               eDebug("[eEPGCache] couldnt initialize schedule other reader!!");
-                               goto error1;
-                       }
-                       m_ScheduleOtherReader->connectRead(slot(*this, &eEPGCache::readScheduleOtherData), m_ScheduleOtherConn);
-                       messages.send(Message(Message::startService, ref));
-                       // -> gotMessage -> changedService
-               }
-       }
-       return;
-error1:
-       m_ScheduleOtherReader=0;
-       m_ScheduleOtherConn=0;
-error2:
-       m_ScheduleReader=0;
-       m_ScheduleConn=0;
-error3:
-       m_NowNextReader=0;
-       m_NowNextConn=0;
-error4:
-       m_currentChannel=0;
-}
-
-void eEPGCache::leaveChannel(iDVBChannel * chan)
-{
-       if ( chan && chan == m_currentChannel )
-       {
-               messages.send(Message(Message::leaveChannel, chan));
-       // -> gotMessage -> abortEPG
-       }
-}
-
-void eEPGCache::changedService(const uniqueEPGKey &service)
-{
-       current_service = service;
-       updateMap::iterator It = serviceLastUpdated.find( current_service );
-
-       int update;
-
-// check if this is a subservice and this is only a dbox2
-// then we dont start epgcache on subservice change..
-// ever and ever..
-
-//     if ( !err || err == -ENOCASYS )
-       {
-               update = ( It != serviceLastUpdated.end() ? ( UPDATE_INTERVAL - ( (time(0)+eDVBLocalTimeHandler::getInstance()->difference()-It->second) * 1000 ) ) : ZAP_DELAY );
-
-               if (update < ZAP_DELAY)
-                       update = ZAP_DELAY;
-
-               zapTimer.start(update, 1);
-               if (update >= 60000)
-                       eDebug("[EPGC] next update in %i min", update/60000);
-               else if (update >= 1000)
-                       eDebug("[EPGC] next update in %i sec", update/1000);
-       }
-
-       Lock();
-       bool empty=eventDB[current_service].first.empty();
-       Unlock();
-
-       if (!empty)
-       {
-               eDebug("[EPGC] yet cached");
-               /*emit*/ EPGAvail(1);
-       }
-       else
-       {
-               eDebug("[EPGC] not cached yet");
-               /*emit*/ EPGAvail(0);
-       }
-}
-
-void eEPGCache::abortEPG()
-{
-       abortTimer.stop();
-       zapTimer.stop();
-       if (isRunning)
-       {
-               if (isRunning & 1)
-               {
-                       isRunning &= ~1;
-                       if ( m_ScheduleReader )
-                               m_ScheduleReader->stop();
-               }
-               if (isRunning & 2)
-               {
-                       isRunning &= ~2;
-                       if ( m_NowNextReader )
-                               m_NowNextReader->stop();
-               }
-               if (isRunning & 4)
-               {
-                       isRunning &= ~4;
-                       if ( m_ScheduleOtherReader )
-                               m_ScheduleOtherReader->stop();
-               }
-               eDebug("[EPGC] abort caching events !!");
-               Lock();
-               temp.clear();
-               Unlock();
-       }
-}
-
 void eEPGCache::gotMessage( const Message &msg )
 {
        switch (msg.type)
@@ -777,19 +532,24 @@ void eEPGCache::gotMessage( const Message &msg )
                case Message::flush:
                        flushEPG(msg.service);
                        break;
-               case Message::startService:
-                       changedService(msg.service);
+               case Message::startChannel:
+               {
+                       singleLock s(channel_map_lock);
+                       channelMapIterator channel =
+                               m_knownChannels.find(msg.channel);
+                       if ( channel != m_knownChannels.end() )
+                               channel->second->startChannel();
                        break;
+               }
                case Message::leaveChannel:
-                       abortEPG();
-                       back_messages.send(Message(Message::leaveChannelFinished));
-                       break;
-               case Message::pause:
-                       pauseEPG();
-                       break;
-               case Message::restart:
-                       restartEPG();
+               {
+                       singleLock s(channel_map_lock);
+                       channelMapIterator channel =
+                               m_knownChannels.find(msg.channel);
+                       if ( channel != m_knownChannels.end() )
+                               channel->second->abortEPG();
                        break;
+               }
                case Message::quit:
                        quit(0);
                        break;
@@ -802,31 +562,6 @@ void eEPGCache::gotMessage( const Message &msg )
        }
 }
 
-void eEPGCache::gotBackMessage( const Message &msg )
-{
-       switch (msg.type)
-       {
-               case Message::leaveChannelFinished:
-                       m_ScheduleOtherReader=0;
-                       m_ScheduleOtherConn=0;
-                       m_ScheduleReader=0;
-                       m_ScheduleConn=0;
-                       m_NowNextReader=0;
-                       m_NowNextConn=0;
-                       m_currentChannel=0;
-                       eDebug("[eEPGC] channel leaved");
-                       if (next_service)
-                       {
-                               startCache(next_service);
-                               next_service = eServiceReferenceDVB();
-                       }
-                       break;
-               default:
-                       eDebug("unhandled EPGCache BackMessage!!");
-                       break;
-       }
-}
-
 void eEPGCache::thread()
 {
        nice(4);
@@ -838,6 +573,7 @@ void eEPGCache::thread()
 
 void eEPGCache::load()
 {
+#if 0
        FILE *f = fopen("/hdd/epg.dat", "r");
        if (f)
        {
@@ -887,10 +623,12 @@ void eEPGCache::load()
                }
                fclose(f);
        }
+#endif
 }
 
 void eEPGCache::save()
 {
+#if 0
        struct statfs s;
        off64_t tmp;
        if (statfs("/hdd", &s)<0)
@@ -945,6 +683,7 @@ void eEPGCache::save()
                        }
                }
        }
+#endif
 }
 
 RESULT eEPGCache::getInstance(ePtr<eEPGCache> &ptr)
@@ -955,3 +694,232 @@ RESULT eEPGCache::getInstance(ePtr<eEPGCache> &ptr)
        return 0;
 }
 
+eEPGCache::channel_data::channel_data(eEPGCache *ml)
+       :cache(ml)
+       ,abortTimer(ml), zapTimer(ml)
+       ,state(0), isRunning(0), haveData(0), can_delete(1)
+{
+       CONNECT(zapTimer.timeout, eEPGCache::channel_data::startEPG);
+       CONNECT(abortTimer.timeout, eEPGCache::channel_data::abortNonAvail);
+}
+
+bool eEPGCache::channel_data::finishEPG()
+{
+       if (!isRunning)  // epg ready
+       {
+               eDebug("[EPGC] stop caching events(%d)", time(0)+eDVBLocalTimeHandler::getInstance()->difference());
+               zapTimer.start(UPDATE_INTERVAL, 1);
+               eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000);
+               for (int i=0; i < 3; ++i)
+               {
+                       seenSections[i].clear();
+                       calcedSections[i].clear();
+               }
+               singleLock l(cache->cache_lock);
+               cache->channelLastUpdated[channel->getChannelID()] = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
+               can_delete=1;
+               return true;
+       }
+       return false;
+}
+
+void eEPGCache::channel_data::startEPG()
+{
+       eDebug("[EPGC] start caching events(%d)", eDVBLocalTimeHandler::getInstance()->difference()+time(0));
+       state=0;
+       haveData=0;
+       can_delete=0;
+       for (int i=0; i < 3; ++i)
+       {
+               seenSections[i].clear();
+               calcedSections[i].clear();
+       }
+
+       eDVBSectionFilterMask mask;
+       memset(&mask, 0, sizeof(mask));
+       mask.pid = 0x12;
+       mask.flags = eDVBSectionFilterMask::rfCRC;
+
+       mask.data[0] = 0x4E;
+       mask.mask[0] = 0xFE;
+       m_NowNextReader->start(mask);
+       isRunning |= NOWNEXT;
+
+       mask.data[0] = 0x50;
+       mask.mask[0] = 0xF0;
+       m_ScheduleReader->start(mask);
+       isRunning |= SCHEDULE;
+
+       mask.data[0] = 0x60;
+       mask.mask[0] = 0xF0;
+       m_ScheduleOtherReader->start(mask);
+       isRunning |= SCHEDULE_OTHER;
+
+       abortTimer.start(7000,true);
+}
+
+void eEPGCache::channel_data::abortNonAvail()
+{
+       if (!state)
+       {
+               if ( !(haveData&eEPGCache::NOWNEXT) && (isRunning&eEPGCache::NOWNEXT) )
+               {
+                       eDebug("[EPGC] abort non avail nownext reading");
+                       isRunning &= ~eEPGCache::NOWNEXT;
+                       if ( m_NowNextReader )
+                               m_NowNextReader->stop();
+               }
+               if ( !(haveData&eEPGCache::SCHEDULE) && (isRunning&eEPGCache::SCHEDULE) )
+               {
+                       eDebug("[EPGC] abort non avail schedule reading");
+                       isRunning &= ~SCHEDULE;
+                       m_ScheduleReader->stop();
+               }
+               if ( !(haveData&eEPGCache::SCHEDULE_OTHER) && (isRunning&eEPGCache::SCHEDULE_OTHER) )
+               {
+                       eDebug("[EPGC] abort non avail schedule_other reading");
+                       isRunning &= ~SCHEDULE_OTHER;
+                       m_ScheduleOtherReader->stop();
+               }
+               if ( isRunning )
+                       abortTimer.start(50000, true);
+               else
+               {
+                       ++state;
+                       for (int i=0; i < 3; ++i)
+                       {
+                               seenSections[i].clear();
+                               calcedSections[i].clear();
+                       }
+                       can_delete=1;
+               }
+       }
+       ++state;
+}
+
+void eEPGCache::channel_data::startChannel()
+{
+       updateMap::iterator It = cache->channelLastUpdated.find( channel->getChannelID() );
+
+       int update = ( It != cache->channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (time(0)+eDVBLocalTimeHandler::getInstance()->difference()-It->second) * 1000 ) ) : ZAP_DELAY );
+
+       if (update < ZAP_DELAY)
+               update = ZAP_DELAY;
+
+       zapTimer.start(update, 1);
+       if (update >= 60000)
+               eDebug("[EPGC] next update in %i min", update/60000);
+       else if (update >= 1000)
+               eDebug("[EPGC] next update in %i sec", update/1000);
+}
+
+void eEPGCache::channel_data::abortEPG()
+{
+       for (int i=0; i < 3; ++i)
+       {
+               seenSections[i].clear();
+               calcedSections[i].clear();
+       }
+       abortTimer.stop();
+       zapTimer.stop();
+       if (isRunning)
+       {
+               eDebug("[EPGC] abort caching events !!");
+               if (isRunning & eEPGCache::SCHEDULE)
+               {
+                       isRunning &= eEPGCache::SCHEDULE;
+                       if ( m_ScheduleReader )
+                               m_ScheduleReader->stop();
+               }
+               if (isRunning & eEPGCache::NOWNEXT)
+               {
+                       isRunning &= ~eEPGCache::NOWNEXT;
+                       if ( m_NowNextReader )
+                               m_NowNextReader->stop();
+               }
+               if (isRunning & SCHEDULE_OTHER)
+               {
+                       isRunning &= ~eEPGCache::SCHEDULE_OTHER;
+                       if ( m_ScheduleOtherReader )
+                               m_ScheduleOtherReader->stop();
+               }
+               can_delete=1;
+       }
+}
+
+void eEPGCache::channel_data::readData( const __u8 *data)
+{
+       if (!data)
+               eDebug("get Null pointer from section reader !!");
+       else
+       {
+               int source;
+               int map;
+               iDVBSectionReader *reader=NULL;
+               switch(data[0])
+               {
+                       case 0x4E ... 0x4F:
+                               reader=m_NowNextReader;
+                               source=eEPGCache::NOWNEXT;
+                               map=0;
+                               break;
+                       case 0x50 ... 0x5F:
+                               reader=m_ScheduleReader;
+                               source=eEPGCache::SCHEDULE;
+                               map=1;
+                               break;
+                       case 0x60 ... 0x6F:
+                               reader=m_ScheduleOtherReader;
+                               source=eEPGCache::SCHEDULE_OTHER;
+                               map=2;
+                               break;
+               }
+               tidMap &seenSections = this->seenSections[map];
+               tidMap &calcedSections = this->calcedSections[map];
+               if ( state == 1 && calcedSections == seenSections || state > 1 )
+               {
+                       eDebugNoNewLine("[EPGC] ");
+                       switch (source)
+                       {
+                               case eEPGCache::NOWNEXT: eDebugNoNewLine("nownext");break;
+                               case eEPGCache::SCHEDULE: eDebugNoNewLine("schedule");break;
+                               case eEPGCache::SCHEDULE_OTHER: eDebugNoNewLine("schedule other");break;
+                               default: eDebugNoNewLine("unknown");break;
+                       }
+                       eDebug(" finished(%d)", time(0)+eDVBLocalTimeHandler::getInstance()->difference());
+                       reader->stop();
+                       isRunning &= ~source;
+                       if (!isRunning)
+                               finishEPG();
+               }
+               else
+               {
+                       eit_t *eit = (eit_t*) data;
+                       __u32 sectionNo = data[0] << 24;
+                       sectionNo |= data[3] << 16;
+                       sectionNo |= data[4] << 8;
+                       sectionNo |= eit->section_number;
+
+                       tidMap::iterator it =
+                               seenSections.find(sectionNo);
+
+                       if ( it == seenSections.end() )
+                       {
+                               seenSections.insert(sectionNo);
+                               __u32 tmpval = sectionNo & 0xFFFFFF00;
+                               __u8 incr = source == NOWNEXT ? 1 : 8;
+                               for ( int i = 0; i <= eit->last_section_number; i+=incr )
+                               {
+                                       if ( i == eit->section_number )
+                                       {
+                                               for (int x=i; x <= eit->segment_last_section_number; ++x)
+                                                       calcedSections.insert(tmpval|(x&0xFF));
+                                       }
+                                       else
+                                               calcedSections.insert(tmpval|(i&0xFF));
+                               }
+                               cache->sectionRead(data, source, this);
+                       }
+               }
+       }
+}