remove unneeded signals ( eDVBChannel::m_stateChanged give us the same informations )
[enigma2.git] / lib / dvb / epgcache.cpp
1 #include <lib/dvb/epgcache.h>
2 #include <lib/dvb/dvb.h>
3
4 #undef EPG_DEBUG  
5
6 #include <time.h>
7 #include <unistd.h>  // for usleep
8 #include <sys/vfs.h> // for statfs
9 #include <libmd5sum.h>
10 #include <lib/base/eerror.h>
11
12 int eventData::CacheSize=0;
13
14 eEPGCache* eEPGCache::instance;
15 pthread_mutex_t eEPGCache::cache_lock=
16         PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
17
18 DEFINE_REF(eEPGCache)
19
20 eEPGCache::eEPGCache()
21         :messages(this,1), back_messages(this,1) ,paused(0)
22         ,CleanTimer(this), zapTimer(this), abortTimer(this)
23 {
24         eDebug("[EPGC] Initialized EPGCache");
25         isRunning=0;
26
27         CONNECT(messages.recv_msg, eEPGCache::gotMessage);
28         CONNECT(back_messages.recv_msg, eEPGCache::gotBackMessage);
29 //      CONNECT(eDVB::getInstance()->switchedService, eEPGCache::enterService);
30 //      CONNECT(eDVB::getInstance()->leaveService, eEPGCache::leaveService);
31         CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated);
32         CONNECT(zapTimer.timeout, eEPGCache::startEPG);
33         CONNECT(CleanTimer.timeout, eEPGCache::cleanLoop);
34         CONNECT(abortTimer.timeout, eEPGCache::abortNonAvail);
35         instance=this;
36 }
37
38 void eEPGCache::timeUpdated()
39 {
40         if ( !thread_running() )
41         {
42                 eDebug("[EPGC] time updated.. start EPG Mainloop");
43                 run();
44         }
45         else
46                 messages.send(Message(Message::timeChanged));
47 }
48
49 int eEPGCache::sectionRead(const __u8 *data, int source)
50 {
51         eit_t *eit = (eit_t*) data;
52
53         int len=HILO(eit->section_length)-1;//+3-4;
54         int ptr=EIT_SIZE;
55         if ( ptr >= len )
56                 return 0;
57
58         //
59         // This fixed the EPG on the Multichoice irdeto systems
60         // the EIT packet is non-compliant.. their EIT packet stinks
61         if ( data[ptr-1] < 0x40 )
62                 --ptr;
63
64         uniqueEPGKey service( HILO(eit->service_id), HILO(eit->original_network_id), HILO(eit->transport_stream_id) );
65         eit_event_struct* eit_event = (eit_event_struct*) (data+ptr);
66         int eit_event_size;
67         int duration;
68
69         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);
70 // FIXME !!! TIME CORRECTION !
71         time_t now = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
72
73         if ( TM != 3599 && TM > -1)
74         {
75                 switch(source)
76                 {
77                 case NOWNEXT:
78                         haveData |= 2;
79                         break;
80                 case SCHEDULE:
81                         haveData |= 1;
82                         break;
83                 case SCHEDULE_OTHER:
84                         haveData |= 4;
85                         break;
86                 }
87         }
88
89         Lock();
90         // hier wird immer eine eventMap zurück gegeben.. entweder eine vorhandene..
91         // oder eine durch [] erzeugte
92         std::pair<eventMap,timeMap> &servicemap = eventDB[service];
93         eventMap::iterator prevEventIt = servicemap.first.end();
94         timeMap::iterator prevTimeIt = servicemap.second.end();
95
96         while (ptr<len)
97         {
98                 eit_event_size = HILO(eit_event->descriptors_loop_length)+EIT_LOOP_SIZE;
99
100                 duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
101                 TM = parseDVBtime(
102                         eit_event->start_time_1,
103                         eit_event->start_time_2,
104                         eit_event->start_time_3,
105                         eit_event->start_time_4,
106                         eit_event->start_time_5);
107
108                 if ( TM == 3599 )
109                         goto next;
110
111                 if ( TM != 3599 && (TM+duration < now || TM > now+14*24*60*60) )
112                         goto next;
113
114                 if ( now <= (TM+duration) || TM == 3599 /*NVOD Service*/ )  // old events should not be cached
115                 {
116                         __u16 event_id = HILO(eit_event->event_id);
117 //                      eDebug("event_id is %d sid is %04x", event_id, service.sid);
118
119                         eventData *evt = 0;
120                         int ev_erase_count = 0;
121                         int tm_erase_count = 0;
122
123 // search in eventmap
124                         eventMap::iterator ev_it =
125                                 servicemap.first.find(event_id);
126
127                         // entry with this event_id is already exist ?
128                         if ( ev_it != servicemap.first.end() )
129                         {
130                                 if ( source > ev_it->second->type )  // update needed ?
131                                         goto next; // when not.. the skip this entry
132 // search this event in timemap
133                                 timeMap::iterator tm_it_tmp = 
134                                         servicemap.second.find(ev_it->second->getStartTime());
135
136                                 if ( tm_it_tmp != servicemap.second.end() )
137                                 {
138                                         if ( tm_it_tmp->first == TM ) // correct eventData
139                                         {
140                                                 // exempt memory
141                                                 delete ev_it->second;
142                                                 evt = new eventData(eit_event, eit_event_size, source);
143                                                 ev_it->second=evt;
144                                                 tm_it_tmp->second=evt;
145                                                 goto next;
146                                         }
147                                         else
148                                         {
149                                                 tm_erase_count++;
150                                                 // delete the found record from timemap
151                                                 servicemap.second.erase(tm_it_tmp);
152                                                 prevTimeIt=servicemap.second.end();
153                                         }
154                                 }
155                         }
156
157 // search in timemap, for check of a case if new time has coincided with time of other event 
158 // or event was is not found in eventmap
159                         timeMap::iterator tm_it =
160                                 servicemap.second.find(TM);
161
162                         if ( tm_it != servicemap.second.end() )
163                         {
164
165 // i think, if event is not found on eventmap, but found on timemap updating nevertheless demands
166 #if 0
167                                 if ( source > tm_it->second->type && tm_erase_count == 0 ) // update needed ?
168                                         goto next; // when not.. the skip this entry
169 #endif
170
171 // search this time in eventmap
172                                 eventMap::iterator ev_it_tmp = 
173                                         servicemap.first.find(tm_it->second->getEventID());
174
175                                 if ( ev_it_tmp != servicemap.first.end() )
176                                 {
177                                         ev_erase_count++;                               
178                                         // delete the found record from eventmap
179                                         servicemap.first.erase(ev_it_tmp);
180                                         prevEventIt=servicemap.first.end();
181                                 }
182                         }
183                         
184                         evt = new eventData(eit_event, eit_event_size, source);
185 #if EPG_DEBUG
186                         bool consistencyCheck=true;
187 #endif
188                         if (ev_erase_count > 0 && tm_erase_count > 0) // 2 different pairs have been removed
189                         {
190                                 // exempt memory
191                                 delete ev_it->second; 
192                                 delete tm_it->second;
193                                 ev_it->second=evt;
194                                 tm_it->second=evt;
195                         }
196                         else if (ev_erase_count == 0 && tm_erase_count > 0) 
197                         {
198                                 // exempt memory
199                                 delete ev_it->second;
200                                 tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
201                                 ev_it->second=evt;
202                         }
203                         else if (ev_erase_count > 0 && tm_erase_count == 0)
204                         {
205                                 // exempt memory
206                                 delete tm_it->second;
207                                 ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) );
208                                 tm_it->second=evt;
209                         }
210                         else // added new eventData
211                         {
212 #if EPG_DEBUG
213                                 consistencyCheck=false;
214 #endif
215                                 prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) );
216                                 prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
217                         }
218 #if EPG_DEBUG
219                         if ( consistencyCheck )
220                         {
221                                 if ( tm_it->second != evt || ev_it->second != evt )
222                                         eFatal("tm_it->second != ev_it->second");
223                                 else if ( tm_it->second->getStartTime() != tm_it->first )
224                                         eFatal("event start_time(%d) non equal timemap key(%d)", 
225                                                 tm_it->second->getStartTime(), tm_it->first );
226                                 else if ( tm_it->first != TM )
227                                         eFatal("timemap key(%d) non equal TM(%d)", 
228                                                 tm_it->first, TM);
229                                 else if ( ev_it->second->getEventID() != ev_it->first )
230                                         eFatal("event_id (%d) non equal event_map key(%d)",
231                                                 ev_it->second->getEventID(), ev_it->first);
232                                 else if ( ev_it->first != event_id )
233                                         eFatal("eventmap key(%d) non equal event_id(%d)", 
234                                                 ev_it->first, event_id );
235                         }
236 #endif
237                 }
238 next:
239 #if EPG_DEBUG
240                 if ( servicemap.first.size() != servicemap.second.size() )
241                 {
242                         FILE *f = fopen("/hdd/event_map.txt", "w+");
243                         int i=0;
244                         for (eventMap::iterator it(servicemap.first.begin())
245                                 ; it != servicemap.first.end(); ++it )
246                                 fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
247                                         i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
248                         fclose(f);
249                         f = fopen("/hdd/time_map.txt", "w+");
250                         i=0;
251                         for (timeMap::iterator it(servicemap.second.begin())
252                                 ; it != servicemap.second.end(); ++it )
253                         fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
254                                 i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
255                         fclose(f);
256
257                         eFatal("(1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d", 
258                                 service.sid, service.tsid, service.onid, 
259                                 servicemap.first.size(), servicemap.second.size() );
260                 }
261 #endif
262                 ptr += eit_event_size;
263                 eit_event=(eit_event_struct*)(((__u8*)eit_event)+eit_event_size);
264         }
265
266         tmpMap::iterator it = temp.find( service );
267         if ( it != temp.end() )
268         {
269                 if ( source > it->second.second )
270                 {
271                         it->second.first=now;
272                         it->second.second=source;
273                 }
274         }
275         else
276                 temp[service] = std::pair< time_t, int> (now, source);
277
278         Unlock();
279
280         return 0;
281 }
282
283 bool eEPGCache::finishEPG()
284 {
285         if (!isRunning)  // epg ready
286         {
287                 eDebug("[EPGC] stop caching events");
288                 zapTimer.start(UPDATE_INTERVAL, 1);
289                 eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000);
290
291                 singleLock l(cache_lock);
292                 tmpMap::iterator It = temp.begin();
293                 abortTimer.stop();
294
295                 while (It != temp.end())
296                 {
297 //                      eDebug("sid = %02x, onid = %02x, type %d", It->first.sid, It->first.onid, It->second.second );
298                         if ( It->second.second == SCHEDULE
299                                 || ( It->second.second == NOWNEXT && !(haveData&1) ) 
300                                 )
301                         {
302 //                              eDebug("ADD to last updated Map");
303                                 serviceLastUpdated[It->first]=It->second.first;
304                         }
305                         if ( eventDB.find( It->first ) == eventDB.end() )
306                         {
307 //                              eDebug("REMOVE from update Map");
308                                 temp.erase(It++);
309                         }
310                         else
311                                 It++;
312                 }
313                 if (!eventDB[current_service].first.empty())
314                         /*emit*/ EPGAvail(1);
315
316                 /*emit*/ EPGUpdated();
317
318                 return true;
319         }
320         return false;
321 }
322
323 void eEPGCache::flushEPG(const uniqueEPGKey & s)
324 {
325         eDebug("[EPGC] flushEPG %d", (int)(bool)s);
326         Lock();
327         if (s)  // clear only this service
328         {
329                 eventCache::iterator it = eventDB.find(s);
330                 if ( it != eventDB.end() )
331                 {
332                         eventMap &evMap = it->second.first;
333                         timeMap &tmMap = it->second.second;
334                         tmMap.clear();
335                         for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
336                                 delete i->second;
337                         evMap.clear();
338                         eventDB.erase(it);
339                         updateMap::iterator u = serviceLastUpdated.find(s);
340                         if ( u != serviceLastUpdated.end() )
341                                 serviceLastUpdated.erase(u);
342                         startEPG();
343                 }
344         }
345         else // clear complete EPG Cache
346         {
347                 for (eventCache::iterator it(eventDB.begin());
348                         it != eventDB.end(); ++it)
349                 {
350                         eventMap &evMap = it->second.first;
351                         timeMap &tmMap = it->second.second;
352                         for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
353                                 delete i->second;
354                         evMap.clear();
355                         tmMap.clear();
356                 }
357                 serviceLastUpdated.clear();
358                 eventDB.clear();
359                 startEPG();
360         }
361         eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
362         Unlock();
363 }
364
365 void eEPGCache::cleanLoop()
366 {
367         singleLock s(cache_lock);
368         if ( isRunning )
369         {
370                 CleanTimer.start(5000,true);
371                 eDebug("[EPGC] schedule cleanloop");
372                 return;
373         }
374         if (!eventDB.empty() && !paused )
375         {
376                 eDebug("[EPGC] start cleanloop");
377                 const eit_event_struct* cur_event;
378                 int duration;
379
380 // FIXME !!! TIME_CORRECTION
381                 time_t now = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
382
383                 for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++)
384                 {
385                         for (timeMap::iterator It = DBIt->second.second.begin(); It != DBIt->second.second.end() && It->first < now;)
386                         {
387                                 cur_event = (*It->second).get();
388                                 duration = fromBCD( cur_event->duration_1)*3600 + fromBCD(cur_event->duration_2)*60 + fromBCD(cur_event->duration_3);
389
390                                 if ( now > (It->first+duration) )  // outdated normal entry (nvod references to)
391                                 {
392                                         // remove entry from eventMap
393                                         eventMap::iterator b(DBIt->second.first.find(It->second->getEventID()));
394                                         if ( b != DBIt->second.first.end() )
395                                         {
396                                                 // release Heap Memory for this entry   (new ....)
397 //                                              eDebug("[EPGC] delete old event (evmap)");
398                                                 DBIt->second.first.erase(b);
399                                         }
400
401                                         // remove entry from timeMap
402 //                                      eDebug("[EPGC] release heap mem");
403                                         delete It->second;
404                                         DBIt->second.second.erase(It++);
405 //                                      eDebug("[EPGC] delete old event (timeMap)");
406
407                                         // add this (changed) service to temp map...
408                                         if ( temp.find(DBIt->first) == temp.end() )
409                                                 temp[DBIt->first]=std::pair<time_t, int>(now, NOWNEXT);
410                                 }
411                                 else
412                                         ++It;
413                         }
414                         if ( DBIt->second.second.size() < 2 )  
415                         // less than two events for this service in cache.. 
416                         {
417                                 updateMap::iterator u = serviceLastUpdated.find(DBIt->first);
418                                 if ( u != serviceLastUpdated.end() )
419                                 {
420                                         // remove from lastupdated map.. 
421                                         serviceLastUpdated.erase(u);
422                                         // current service?
423                                         if ( DBIt->first == current_service )
424                                         {
425                                         // immediate .. after leave cleanloop 
426                                         // update epgdata for this service
427                                                 zapTimer.start(0,true);
428                                         }
429                                 }
430                         }
431                 }
432
433                 if (temp.size())
434                         /*emit*/ EPGUpdated();
435
436                 eDebug("[EPGC] stop cleanloop");
437                 eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
438         }
439         CleanTimer.start(CLEAN_INTERVAL,true);
440 }
441
442 eEPGCache::~eEPGCache()
443 {
444         messages.send(Message::quit);
445         kill(); // waiting for thread shutdown
446         Lock();
447         for (eventCache::iterator evIt = eventDB.begin(); evIt != eventDB.end(); evIt++)
448                 for (eventMap::iterator It = evIt->second.first.begin(); It != evIt->second.first.end(); It++)
449                         delete It->second;
450         Unlock();
451 }
452
453 Event *eEPGCache::lookupEvent(const eServiceReferenceDVB &service, int event_id, bool plain)
454 {
455         singleLock s(cache_lock);
456         uniqueEPGKey key( service );
457
458         eventCache::iterator It = eventDB.find( key );
459         if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached?
460         {
461                 eventMap::iterator i( It->second.first.find( event_id ));
462                 if ( i != It->second.first.end() )
463                 {
464                         if ( service.getServiceType() == 4 ) // nvod ref
465                                 return lookupEvent( service, i->second->getStartTime(), plain );
466                         else if ( plain )
467                 // get plain data... not in Event Format !!!
468                 // before use .. cast it to eit_event_struct*
469                                 return (Event*) i->second->get();
470                         else
471                                 return new Event( (uint8_t*)i->second->get() /*, (It->first.tsid<<16)|It->first.onid*/ );
472                 }
473                 else
474                         eDebug("event %04x not found in epgcache", event_id);
475         }
476         return 0;
477 }
478
479 Event *eEPGCache::lookupEvent(const eServiceReferenceDVB &service, time_t t, bool plain )
480 // if t == 0 we search the current event...
481 {
482         singleLock s(cache_lock);
483         uniqueEPGKey key(service);
484
485         // check if EPG for this service is ready...
486         eventCache::iterator It = eventDB.find( key );
487         if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached ?
488         {
489                 if (!t)
490                         t = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
491
492                 timeMap::iterator i = It->second.second.lower_bound(t);
493                 if ( i != It->second.second.end() )
494                 {
495                         i--;
496                         if ( i != It->second.second.end() )
497                         {
498                                 const eit_event_struct* eit_event = i->second->get();
499                                 int duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
500                                 if ( t <= i->first+duration )
501                                 {
502                                         if ( plain )
503                                                 // get plain data... not in Event Format !!!
504                                                 // before use .. cast it to eit_event_struct*
505                                                 return (Event*) i->second->get();
506                                         return new Event( (uint8_t*)i->second->get() /*, (It->first.tsid<<16)|It->first.onid */ );
507                                 }
508                         }
509                 }
510
511                 for ( eventMap::iterator i( It->second.first.begin() ); i != It->second.first.end(); i++)
512                 {
513                         const eit_event_struct* eit_event = i->second->get();
514                         int duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
515                         time_t begTime = 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);
516                         if ( t >= begTime && t <= begTime+duration) // then we have found
517                         {
518                                 if ( plain )
519                                         // get plain data... not in Event Format !!!
520                                         // before use .. cast it to eit_event_struct*
521                                         return (Event*) i->second->get();
522                                 return new Event( (uint8_t*)i->second->get()/*, (It->first.tsid<<16)|It->first.onid*/ );
523                         }
524                 }
525         }
526         return 0;
527 }
528
529 void eEPGCache::pauseEPG()
530 {
531         if (!paused)
532         {
533                 abortEPG();
534                 eDebug("[EPGC] paused]");
535                 paused=1;
536         }
537 }
538
539 void eEPGCache::restartEPG()
540 {
541         if (paused)
542         {
543                 isRunning=0;
544                 eDebug("[EPGC] restarted");
545                 paused--;
546                 if (paused)
547                 {
548                         paused = 0;
549                         startEPG();   // updateEPG
550                 }
551                 cleanLoop();
552         }
553 }
554
555 void eEPGCache::startEPG()
556 {
557         if (paused)  // called from the updateTimer during pause...
558         {
559                 paused++;
560                 return;
561         }
562         if (eDVBLocalTimeHandler::getInstance()->ready())
563         {
564                 Lock();
565                 temp.clear();
566                 Unlock();
567                 eDebug("[EPGC] start caching events");
568                 state=0;
569                 haveData=0;
570
571                 eDVBSectionFilterMask mask;
572                 memset(&mask, 0, sizeof(mask));
573                 mask.pid = 0x12;
574                 mask.flags = eDVBSectionFilterMask::rfCRC;
575
576                 mask.data[0] = 0x4E;
577                 mask.mask[0] = 0xFE;
578                 m_NowNextReader->start(mask);
579                 isRunning |= 1;
580
581                 mask.data[0] = 0x50;
582                 mask.mask[0] = 0xF0;
583                 m_ScheduleReader->start(mask);
584                 isRunning |= 2;
585
586                 mask.data[0] = 0x60;
587                 mask.mask[0] = 0xF0;
588                 m_ScheduleOtherReader->start(mask);
589                 isRunning |= 4;
590
591                 abortTimer.start(5000,true);
592         }
593         else
594         {
595                 eDebug("[EPGC] wait for clock update");
596                 zapTimer.start(1000, 1); // restart Timer
597         }
598 }
599
600 void eEPGCache::abortNonAvail()
601 {
602         if (!state)
603         {
604                 if ( !(haveData&2) && (isRunning&2) )
605                 {
606                         eDebug("[EPGC] abort non avail nownext reading");
607                         isRunning &= ~2;
608                         if ( m_NowNextReader )
609                                 m_NowNextReader->stop();
610                 }
611                 if ( !(haveData&1) && (isRunning&1) )
612                 {
613                         eDebug("[EPGC] abort non avail schedule reading");
614                         isRunning &= ~1;
615                         m_ScheduleReader->stop();
616                 }
617                 if ( !(haveData&4) && (isRunning&4) )
618                 {
619                         eDebug("[EPGC] abort non avail schedule_other reading");
620                         isRunning &= ~4;
621                         m_ScheduleOtherReader->stop();
622                 }
623                 abortTimer.start(20000, true);
624         }
625         ++state;
626 }
627
628 void eEPGCache::startCache(const eServiceReferenceDVB& ref)
629 {
630         if ( m_currentChannel )
631         {
632                 next_service = ref;
633                 leaveChannel(m_currentChannel);
634                 return;
635         }
636         eDVBChannelID chid;
637         ref.getChannelID( chid );
638         ePtr<eDVBResourceManager> res_mgr;
639         if ( eDVBResourceManager::getInstance( res_mgr ) )
640                 eDebug("[eEPGCache] no res manager!!");
641         else
642         {
643                 ePtr<iDVBDemux> demux;
644 //              res_mgr->allocateChannel(chid, m_currentChannel);
645                 if ( m_currentChannel->getDemux(demux) )
646                 {
647                         eDebug("[eEPGCache] no demux!!");
648                         goto error4;
649                 }
650                 else
651                 {
652                         RESULT res;
653                         m_NowNextReader = new eDVBSectionReader( demux, this, res );
654                         if ( res )
655                         {
656                                 eDebug("[eEPGCache] couldnt initialize nownext reader!!");
657                                 goto error3;
658                         }
659                         m_NowNextReader->connectRead(slot(*this, &eEPGCache::readNowNextData), m_NowNextConn);
660                         m_ScheduleReader = new eDVBSectionReader( demux, this, res );
661                         if ( res )
662                         {
663                                 eDebug("[eEPGCache] couldnt initialize schedule reader!!");
664                                 goto error2;
665                         }
666                         m_ScheduleReader->connectRead(slot(*this, &eEPGCache::readScheduleData), m_ScheduleConn);
667                         m_ScheduleOtherReader = new eDVBSectionReader( demux, this, res );
668                         if ( res )
669                         {
670                                 eDebug("[eEPGCache] couldnt initialize schedule other reader!!");
671                                 goto error1;
672                         }
673                         m_ScheduleOtherReader->connectRead(slot(*this, &eEPGCache::readScheduleOtherData), m_ScheduleOtherConn);
674                         messages.send(Message(Message::startService, ref));
675                         // -> gotMessage -> changedService
676                 }
677         }
678         return;
679 error1:
680         m_ScheduleOtherReader=0;
681         m_ScheduleOtherConn=0;
682 error2:
683         m_ScheduleReader=0;
684         m_ScheduleConn=0;
685 error3:
686         m_NowNextReader=0;
687         m_NowNextConn=0;
688 error4:
689         m_currentChannel=0;
690 }
691
692 void eEPGCache::leaveChannel(iDVBChannel * chan)
693 {
694         if ( chan && chan == m_currentChannel )
695         {
696                 messages.send(Message(Message::leaveChannel, chan));
697         // -> gotMessage -> abortEPG
698         }
699 }
700
701 void eEPGCache::changedService(const uniqueEPGKey &service)
702 {
703         current_service = service;
704         updateMap::iterator It = serviceLastUpdated.find( current_service );
705
706         int update;
707
708 // check if this is a subservice and this is only a dbox2
709 // then we dont start epgcache on subservice change..
710 // ever and ever..
711
712 //      if ( !err || err == -ENOCASYS )
713         {
714                 update = ( It != serviceLastUpdated.end() ? ( UPDATE_INTERVAL - ( (time(0)+eDVBLocalTimeHandler::getInstance()->difference()-It->second) * 1000 ) ) : ZAP_DELAY );
715
716                 if (update < ZAP_DELAY)
717                         update = ZAP_DELAY;
718
719                 zapTimer.start(update, 1);
720                 if (update >= 60000)
721                         eDebug("[EPGC] next update in %i min", update/60000);
722                 else if (update >= 1000)
723                         eDebug("[EPGC] next update in %i sec", update/1000);
724         }
725
726         Lock();
727         bool empty=eventDB[current_service].first.empty();
728         Unlock();
729
730         if (!empty)
731         {
732                 eDebug("[EPGC] yet cached");
733                 /*emit*/ EPGAvail(1);
734         }
735         else
736         {
737                 eDebug("[EPGC] not cached yet");
738                 /*emit*/ EPGAvail(0);
739         }
740 }
741
742 void eEPGCache::abortEPG()
743 {
744         abortTimer.stop();
745         zapTimer.stop();
746         if (isRunning)
747         {
748                 if (isRunning & 1)
749                 {
750                         isRunning &= ~1;
751                         if ( m_ScheduleReader )
752                                 m_ScheduleReader->stop();
753                 }
754                 if (isRunning & 2)
755                 {
756                         isRunning &= ~2;
757                         if ( m_NowNextReader )
758                                 m_NowNextReader->stop();
759                 }
760                 if (isRunning & 4)
761                 {
762                         isRunning &= ~4;
763                         if ( m_ScheduleOtherReader )
764                                 m_ScheduleOtherReader->stop();
765                 }
766                 eDebug("[EPGC] abort caching events !!");
767                 Lock();
768                 temp.clear();
769                 Unlock();
770         }
771 }
772
773 void eEPGCache::gotMessage( const Message &msg )
774 {
775         switch (msg.type)
776         {
777                 case Message::flush:
778                         flushEPG(msg.service);
779                         break;
780                 case Message::startService:
781                         changedService(msg.service);
782                         break;
783                 case Message::leaveChannel:
784                         abortEPG();
785                         back_messages.send(Message(Message::leaveChannelFinished));
786                         break;
787                 case Message::pause:
788                         pauseEPG();
789                         break;
790                 case Message::restart:
791                         restartEPG();
792                         break;
793                 case Message::quit:
794                         quit(0);
795                         break;
796                 case Message::timeChanged:
797                         cleanLoop();
798                         break;
799                 default:
800                         eDebug("unhandled EPGCache Message!!");
801                         break;
802         }
803 }
804
805 void eEPGCache::gotBackMessage( const Message &msg )
806 {
807         switch (msg.type)
808         {
809                 case Message::leaveChannelFinished:
810                         m_ScheduleOtherReader=0;
811                         m_ScheduleOtherConn=0;
812                         m_ScheduleReader=0;
813                         m_ScheduleConn=0;
814                         m_NowNextReader=0;
815                         m_NowNextConn=0;
816                         m_currentChannel=0;
817                         eDebug("[eEPGC] channel leaved");
818                         if (next_service)
819                         {
820                                 startCache(next_service);
821                                 next_service = eServiceReferenceDVB();
822                         }
823                         break;
824                 default:
825                         eDebug("unhandled EPGCache BackMessage!!");
826                         break;
827         }
828 }
829
830 void eEPGCache::thread()
831 {
832         nice(4);
833         load();
834         cleanLoop();
835         exec();
836         save();
837 }
838
839 void eEPGCache::load()
840 {
841         FILE *f = fopen("/hdd/epg.dat", "r");
842         if (f)
843         {
844                 unsigned char md5_saved[16];
845                 unsigned char md5[16];
846                 int size=0;
847                 int cnt=0;
848                 bool md5ok=false;
849                 if (!md5_file("/hdd/epg.dat", 1, md5))
850                 {
851                         FILE *f = fopen("/hdd/epg.dat.md5", "r");
852                         if (f)
853                         {
854                                 fread( md5_saved, 16, 1, f);
855                                 fclose(f);
856                                 if ( !memcmp(md5_saved, md5, 16) )
857                                         md5ok=true;
858                         }
859                 }
860                 if ( md5ok )
861                 {
862                         fread( &size, sizeof(int), 1, f);
863                         while(size--)
864                         {
865                                 uniqueEPGKey key;
866                                 eventMap evMap;
867                                 timeMap tmMap;
868                                 int size=0;
869                                 fread( &key, sizeof(uniqueEPGKey), 1, f);
870                                 fread( &size, sizeof(int), 1, f);
871                                 while(size--)
872                                 {
873                                         int len=0;
874                                         int type=0;
875                                         eventData *event=0;
876                                         fread( &type, sizeof(int), 1, f);
877                                         fread( &len, sizeof(int), 1, f);
878                                         event = new eventData(0, len, type);
879                                         fread( event->EITdata, len, 1, f);
880                                         evMap[ event->getEventID() ]=event;
881                                         tmMap[ event->getStartTime() ]=event;
882                                         ++cnt;
883                                 }
884                                 eventDB[key]=std::pair<eventMap,timeMap>(evMap,tmMap);
885                         }
886                         eDebug("%d events read from /hdd/epg.dat.md5", cnt);
887                 }
888                 fclose(f);
889         }
890 }
891
892 void eEPGCache::save()
893 {
894         struct statfs s;
895         off64_t tmp;
896         if (statfs("/hdd", &s)<0)
897                 tmp=0;
898         else
899         {
900                 tmp=s.f_blocks;
901                 tmp*=s.f_bsize;
902         }
903
904         // prevent writes to builtin flash
905         if ( tmp < 1024*1024*50 ) // storage size < 50MB
906                 return;
907
908         // check for enough free space on storage
909         tmp=s.f_bfree;
910         tmp*=s.f_bsize;
911         if ( tmp < (eventData::CacheSize*12)/10 ) // 20% overhead
912                 return;
913
914         FILE *f = fopen("/hdd/epg.dat", "w");
915         int cnt=0;
916         if ( f )
917         {
918                 int size = eventDB.size();
919                 fwrite( &size, sizeof(int), 1, f );
920                 for (eventCache::iterator service_it(eventDB.begin()); service_it != eventDB.end(); ++service_it)
921                 {
922                         timeMap &timemap = service_it->second.second;
923                         fwrite( &service_it->first, sizeof(uniqueEPGKey), 1, f);
924                         size = timemap.size();
925                         fwrite( &size, sizeof(int), 1, f);
926                         for (timeMap::iterator time_it(timemap.begin()); time_it != timemap.end(); ++time_it)
927                         {
928                                 int len = time_it->second->ByteSize;
929                                 fwrite( &time_it->second->type, sizeof(int), 1, f );
930                                 fwrite( &len, sizeof(int), 1, f);
931                                 fwrite( time_it->second->EITdata, len, 1, f);
932                                 ++cnt;
933                         }
934                 }
935                 eDebug("%d events written to /hdd/epg.dat", cnt);
936                 fclose(f);
937                 unsigned char md5[16];
938                 if (!md5_file("/hdd/epg.dat", 1, md5))
939                 {
940                         FILE *f = fopen("/hdd/epg.dat.md5", "w");
941                         if (f)
942                         {
943                                 fwrite( md5, 16, 1, f);
944                                 fclose(f);
945                         }
946                 }
947         }
948 }
949
950 RESULT eEPGCache::getInstance(ePtr<eEPGCache> &ptr)
951 {
952         ptr = instance;
953         if (!ptr)
954                 return -1;
955         return 0;
956 }
957