fix show currently running events in channellist ( in favourite list )
[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 descriptorMap eventData::descriptors;
14 __u8 eventData::data[4108];
15 extern const uint32_t crc32_table[256];
16
17 eventData::eventData(const eit_event_struct* e, int size, int type)
18         :ByteSize(size&0xFF), type(type&0xFF)
19 {
20         if (!e)
21                 return;
22
23         __u32 descr[65];
24         __u32 *pdescr=descr;
25
26         __u8 *data = (__u8*)e;
27         int ptr=10;
28         int descriptors_length = (data[ptr++]&0x0F) << 8;
29         descriptors_length |= data[ptr++];
30         while ( descriptors_length > 0 )
31         {
32                 __u8 *descr = data+ptr;
33                 int descr_len = descr[1]+2;
34
35                 __u32 crc = 0;
36                 int cnt=0;
37                 while(cnt++ < descr_len)
38                         crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ data[ptr++]) & 0xFF];
39
40                 descriptorMap::iterator it =
41                         descriptors.find(crc);
42                 if ( it == descriptors.end() )
43                 {
44                         CacheSize+=descr_len;
45                         __u8 *d = new __u8[descr_len];
46                         memcpy(d, descr, descr_len);
47                         descriptors[crc] = descriptorPair(1, d);
48                 }
49                 else
50                         ++it->second.first;
51
52                 *pdescr++=crc;
53                 descriptors_length -= descr_len;
54         }
55         ByteSize = 12+((pdescr-descr)*4);
56         EITdata = new __u8[ByteSize];
57         CacheSize+=ByteSize;
58         memcpy(EITdata, (__u8*) e, 12);
59         memcpy(EITdata+12, descr, ByteSize-12);
60 }
61
62 const eit_event_struct* eventData::get() const
63 {
64         int pos = 12;
65         int tmp = ByteSize-12;
66
67         memcpy(data, EITdata, 12);
68         __u32 *p = (__u32*)(EITdata+12);
69         while(tmp>0)
70         {
71                 descriptorMap::iterator it =
72                         descriptors.find(*p++);
73                 if ( it != descriptors.end() )
74                 {
75                         int b = it->second.second[1]+2;
76                         memcpy(data+pos, it->second.second, b );
77                         pos += b;
78                 }
79                 tmp-=4;
80         }
81
82         return (const eit_event_struct*)data;
83 }
84
85 eventData::~eventData()
86 {
87         if ( ByteSize )
88         {
89                 CacheSize-=ByteSize;
90                 ByteSize-=12;
91                 __u32 *d = (__u32*)(EITdata+12);
92                 while(ByteSize)
93                 {
94                         descriptorMap::iterator it =
95                                 descriptors.find(*d++);
96                         if ( it != descriptors.end() )
97                         {
98                                 descriptorPair &p = it->second;
99                                 if (!--p.first) // no more used descriptor
100                                 {
101                                         CacheSize -= it->second.second[1];
102                                         delete [] it->second.second;    // free descriptor memory
103                                         descriptors.erase(it);  // remove entry from descriptor map
104                                 }
105                         }
106                         ByteSize-=4;
107                 }
108                 delete [] EITdata;
109         }
110 }
111
112 void eventData::load(FILE *f)
113 {
114         int size=0;
115         int id=0;
116         __u8 header[2];
117         descriptorPair p;
118         fread(&size, sizeof(int), 1, f);
119         while(size)
120         {
121                 fread(&id, sizeof(__u32), 1, f);
122                 fread(&p.first, sizeof(int), 1, f);
123                 fread(header, 2, 1, f);
124                 int bytes = header[1]+2;
125                 p.second = new __u8[bytes];
126                 p.second[0] = header[0];
127                 p.second[1] = header[1];
128                 fread(p.second+2, bytes-2, 1, f);
129                 descriptors[id]=p;
130                 --size;
131                 CacheSize+=bytes;
132         }
133 }
134
135 void eventData::save(FILE *f)
136 {
137         int size=descriptors.size();
138         descriptorMap::iterator it(descriptors.begin());
139         fwrite(&size, sizeof(int), 1, f);
140         while(size)
141         {
142                 fwrite(&it->first, sizeof(__u32), 1, f);
143                 fwrite(&it->second.first, sizeof(int), 1, f);
144                 fwrite(it->second.second, it->second.second[1]+2, 1, f);
145                 ++it;
146                 --size;
147         }
148 }
149
150 eEPGCache* eEPGCache::instance;
151 pthread_mutex_t eEPGCache::cache_lock=
152         PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
153 pthread_mutex_t eEPGCache::channel_map_lock=
154         PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
155
156 DEFINE_REF(eEPGCache)
157
158 eEPGCache::eEPGCache()
159         :messages(this,1), cleanTimer(this)//, paused(0)
160 {
161         eDebug("[EPGC] Initialized EPGCache");
162
163         CONNECT(messages.recv_msg, eEPGCache::gotMessage);
164         CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated);
165         CONNECT(cleanTimer.timeout, eEPGCache::cleanLoop);
166
167         ePtr<eDVBResourceManager> res_mgr;
168         eDVBResourceManager::getInstance(res_mgr);
169         if (!res_mgr)
170                 eDebug("[eEPGCache] no resource manager !!!!!!!");
171         else
172                 res_mgr->connectChannelAdded(slot(*this,&eEPGCache::DVBChannelAdded), m_chanAddedConn);
173         instance=this;
174 }
175
176 void eEPGCache::timeUpdated()
177 {
178         if ( !thread_running() )
179         {
180                 eDebug("[EPGC] time updated.. start EPG Mainloop");
181                 run();
182         }
183         else
184                 messages.send(Message(Message::timeChanged));
185 }
186
187 void eEPGCache::DVBChannelAdded(eDVBChannel *chan)
188 {
189         if ( chan )
190         {
191 //              eDebug("[eEPGCache] add channel %p", chan);
192                 channel_data *data = new channel_data(this);
193                 data->channel = chan;
194                 singleLock s(channel_map_lock);
195                 m_knownChannels.insert( std::pair<iDVBChannel*, channel_data* >(chan, data) );
196                 chan->connectStateChange(slot(*this, &eEPGCache::DVBChannelStateChanged), data->m_stateChangedConn);
197         }
198 }
199
200 void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
201 {
202         singleLock s(channel_map_lock);
203         channelMapIterator it =
204                 m_knownChannels.find(chan);
205         if ( it == m_knownChannels.end() )
206                 eDebug("[eEPGCache] will start non existing channel %p !!!", chan);
207         else
208         {
209                 channel_data &data = *it->second;
210                 ePtr<eDVBResourceManager> res_mgr;
211                 if ( eDVBResourceManager::getInstance( res_mgr ) )
212                         eDebug("[eEPGCache] no res manager!!");
213                 else
214                 {
215                         ePtr<iDVBDemux> demux;
216                         if ( data.channel->getDemux(demux, 0) )
217                         {
218                                 eDebug("[eEPGCache] no demux!!");
219                                 return;
220                         }
221                         else
222                         {
223                                 RESULT res = demux->createSectionReader( this, data.m_NowNextReader );
224                                 if ( res )
225                                 {
226                                         eDebug("[eEPGCache] couldnt initialize nownext reader!!");
227                                         return;
228                                 }
229
230                                 res = demux->createSectionReader( this, data.m_ScheduleReader );
231                                 if ( res )
232                                 {
233                                         eDebug("[eEPGCache] couldnt initialize schedule reader!!");
234                                         return;
235                                 }
236
237                                 res = demux->createSectionReader( this, data.m_ScheduleOtherReader );
238                                 if ( res )
239                                 {
240                                         eDebug("[eEPGCache] couldnt initialize schedule other reader!!");
241                                         return;
242                                 }
243
244                                 messages.send(Message(Message::startChannel, chan));
245                                 // -> gotMessage -> changedService
246                         }
247                 }
248         }
249 }
250
251 void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan)
252 {
253         channelMapIterator it =
254                 m_knownChannels.find(chan);
255         if ( it != m_knownChannels.end() )
256         {
257                 int state=0;
258                 chan->getState(state);
259                 switch (state)
260                 {
261                         case iDVBChannel::state_ok:
262                         {
263                                 eDebug("[eEPGCache] channel %p running", chan);
264                                 DVBChannelRunning(chan);
265                                 break;
266                         }
267                         case iDVBChannel::state_release:
268                         {
269                                 eDebug("[eEPGCache] remove channel %p", chan);
270                                 messages.send(Message(Message::leaveChannel, chan));
271                                 while(!it->second->can_delete)
272                                         usleep(1000);
273                                 delete it->second;
274                                 m_knownChannels.erase(it);
275                                 // -> gotMessage -> abortEPG
276                                 break;
277                         }
278                 }
279         }
280 }
281
282 void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
283 {
284         eit_t *eit = (eit_t*) data;
285
286         int len=HILO(eit->section_length)-1;//+3-4;
287         int ptr=EIT_SIZE;
288         if ( ptr >= len )
289                 return;
290
291         // This fixed the EPG on the Multichoice irdeto systems
292         // the EIT packet is non-compliant.. their EIT packet stinks
293         if ( data[ptr-1] < 0x40 )
294                 --ptr;
295
296         uniqueEPGKey service( HILO(eit->service_id), HILO(eit->original_network_id), HILO(eit->transport_stream_id) );
297         eit_event_struct* eit_event = (eit_event_struct*) (data+ptr);
298         int eit_event_size;
299         int duration;
300
301         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);
302         time_t now = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
303
304         if ( TM != 3599 && TM > -1)
305                 channel->haveData |= source;
306
307         singleLock s(cache_lock);
308         // hier wird immer eine eventMap zurück gegeben.. entweder eine vorhandene..
309         // oder eine durch [] erzeugte
310         std::pair<eventMap,timeMap> &servicemap = eventDB[service];
311         eventMap::iterator prevEventIt = servicemap.first.end();
312         timeMap::iterator prevTimeIt = servicemap.second.end();
313
314         while (ptr<len)
315         {
316                 eit_event_size = HILO(eit_event->descriptors_loop_length)+EIT_LOOP_SIZE;
317
318                 duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
319                 TM = parseDVBtime(
320                         eit_event->start_time_1,
321                         eit_event->start_time_2,
322                         eit_event->start_time_3,
323                         eit_event->start_time_4,
324                         eit_event->start_time_5);
325
326                 if ( TM == 3599 )
327                         goto next;
328
329                 if ( TM != 3599 && (TM+duration < now || TM > now+14*24*60*60) )
330                         goto next;
331
332                 if ( now <= (TM+duration) || TM == 3599 /*NVOD Service*/ )  // old events should not be cached
333                 {
334                         __u16 event_id = HILO(eit_event->event_id);
335 //                      eDebug("event_id is %d sid is %04x", event_id, service.sid);
336
337                         eventData *evt = 0;
338                         int ev_erase_count = 0;
339                         int tm_erase_count = 0;
340
341                         // search in eventmap
342                         eventMap::iterator ev_it =
343                                 servicemap.first.find(event_id);
344
345                         // entry with this event_id is already exist ?
346                         if ( ev_it != servicemap.first.end() )
347                         {
348                                 if ( source > ev_it->second->type )  // update needed ?
349                                         goto next; // when not.. the skip this entry
350
351                                 // search this event in timemap
352                                 timeMap::iterator tm_it_tmp = 
353                                         servicemap.second.find(ev_it->second->getStartTime());
354
355                                 if ( tm_it_tmp != servicemap.second.end() )
356                                 {
357                                         if ( tm_it_tmp->first == TM ) // correct eventData
358                                         {
359                                                 // exempt memory
360                                                 delete ev_it->second;
361                                                 evt = new eventData(eit_event, eit_event_size, source);
362                                                 ev_it->second=evt;
363                                                 tm_it_tmp->second=evt;
364                                                 goto next;
365                                         }
366                                         else
367                                         {
368                                                 tm_erase_count++;
369                                                 // delete the found record from timemap
370                                                 servicemap.second.erase(tm_it_tmp);
371                                                 prevTimeIt=servicemap.second.end();
372                                         }
373                                 }
374                         }
375
376                         // search in timemap, for check of a case if new time has coincided with time of other event 
377                         // or event was is not found in eventmap
378                         timeMap::iterator tm_it =
379                                 servicemap.second.find(TM);
380
381                         if ( tm_it != servicemap.second.end() )
382                         {
383                                 // i think, if event is not found on eventmap, but found on timemap updating nevertheless demands
384 #if 0
385                                 if ( source > tm_it->second->type && tm_erase_count == 0 ) // update needed ?
386                                         goto next; // when not.. the skip this entry
387 #endif
388
389                                 // search this time in eventmap
390                                 eventMap::iterator ev_it_tmp = 
391                                         servicemap.first.find(tm_it->second->getEventID());
392
393                                 if ( ev_it_tmp != servicemap.first.end() )
394                                 {
395                                         ev_erase_count++;                               
396                                         // delete the found record from eventmap
397                                         servicemap.first.erase(ev_it_tmp);
398                                         prevEventIt=servicemap.first.end();
399                                 }
400                         }
401                         
402                         evt = new eventData(eit_event, eit_event_size, source);
403 #if EPG_DEBUG
404                         bool consistencyCheck=true;
405 #endif
406                         if (ev_erase_count > 0 && tm_erase_count > 0) // 2 different pairs have been removed
407                         {
408                                 // exempt memory
409                                 delete ev_it->second; 
410                                 delete tm_it->second;
411                                 ev_it->second=evt;
412                                 tm_it->second=evt;
413                         }
414                         else if (ev_erase_count == 0 && tm_erase_count > 0) 
415                         {
416                                 // exempt memory
417                                 delete ev_it->second;
418                                 tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
419                                 ev_it->second=evt;
420                         }
421                         else if (ev_erase_count > 0 && tm_erase_count == 0)
422                         {
423                                 // exempt memory
424                                 delete tm_it->second;
425                                 ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) );
426                                 tm_it->second=evt;
427                         }
428                         else // added new eventData
429                         {
430 #if EPG_DEBUG
431                                 consistencyCheck=false;
432 #endif
433                                 prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) );
434                                 prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
435                         }
436 #if EPG_DEBUG
437                         if ( consistencyCheck )
438                         {
439                                 if ( tm_it->second != evt || ev_it->second != evt )
440                                         eFatal("tm_it->second != ev_it->second");
441                                 else if ( tm_it->second->getStartTime() != tm_it->first )
442                                         eFatal("event start_time(%d) non equal timemap key(%d)", 
443                                                 tm_it->second->getStartTime(), tm_it->first );
444                                 else if ( tm_it->first != TM )
445                                         eFatal("timemap key(%d) non equal TM(%d)", 
446                                                 tm_it->first, TM);
447                                 else if ( ev_it->second->getEventID() != ev_it->first )
448                                         eFatal("event_id (%d) non equal event_map key(%d)",
449                                                 ev_it->second->getEventID(), ev_it->first);
450                                 else if ( ev_it->first != event_id )
451                                         eFatal("eventmap key(%d) non equal event_id(%d)", 
452                                                 ev_it->first, event_id );
453                         }
454 #endif
455                 }
456 next:
457 #if EPG_DEBUG
458                 if ( servicemap.first.size() != servicemap.second.size() )
459                 {
460                         FILE *f = fopen("/hdd/event_map.txt", "w+");
461                         int i=0;
462                         for (eventMap::iterator it(servicemap.first.begin())
463                                 ; it != servicemap.first.end(); ++it )
464                                 fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
465                                         i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
466                         fclose(f);
467                         f = fopen("/hdd/time_map.txt", "w+");
468                         i=0;
469                         for (timeMap::iterator it(servicemap.second.begin())
470                                 ; it != servicemap.second.end(); ++it )
471                                         fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", 
472                                                 i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
473                         fclose(f);
474
475                         eFatal("(1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d", 
476                                 service.sid, service.tsid, service.onid, 
477                                 servicemap.first.size(), servicemap.second.size() );
478                 }
479 #endif
480                 ptr += eit_event_size;
481                 eit_event=(eit_event_struct*)(((__u8*)eit_event)+eit_event_size);
482         }
483 }
484
485 void eEPGCache::flushEPG(const uniqueEPGKey & s)
486 {
487         eDebug("[EPGC] flushEPG %d", (int)(bool)s);
488         singleLock l(cache_lock);
489         if (s)  // clear only this service
490         {
491                 eventCache::iterator it = eventDB.find(s);
492                 if ( it != eventDB.end() )
493                 {
494                         eventMap &evMap = it->second.first;
495                         timeMap &tmMap = it->second.second;
496                         tmMap.clear();
497                         for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
498                                 delete i->second;
499                         evMap.clear();
500                         eventDB.erase(it);
501
502                         // TODO .. search corresponding channel for removed service and remove this channel from lastupdated map
503                 }
504         }
505         else // clear complete EPG Cache
506         {
507                 for (eventCache::iterator it(eventDB.begin());
508                         it != eventDB.end(); ++it)
509                 {
510                         eventMap &evMap = it->second.first;
511                         timeMap &tmMap = it->second.second;
512                         for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
513                                 delete i->second;
514                         evMap.clear();
515                         tmMap.clear();
516                 }
517                 eventDB.clear();
518                 channelLastUpdated.clear();
519                 singleLock m(channel_map_lock);
520                 for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
521                         it->second->startEPG();
522         }
523         eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
524 }
525
526 void eEPGCache::cleanLoop()
527 {
528         singleLock s(cache_lock);
529         if (!eventDB.empty())
530         {
531                 eDebug("[EPGC] start cleanloop");
532
533                 time_t now = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
534
535                 for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++)
536                 {
537                         for (timeMap::iterator It = DBIt->second.second.begin(); It != DBIt->second.second.end() && It->first < now;)
538                         {
539                                 if ( now > (It->first+It->second->getDuration()) )  // outdated normal entry (nvod references to)
540                                 {
541                                         // remove entry from eventMap
542                                         eventMap::iterator b(DBIt->second.first.find(It->second->getEventID()));
543                                         if ( b != DBIt->second.first.end() )
544                                         {
545                                                 // release Heap Memory for this entry   (new ....)
546 //                                              eDebug("[EPGC] delete old event (evmap)");
547                                                 DBIt->second.first.erase(b);
548                                         }
549
550                                         // remove entry from timeMap
551 //                                      eDebug("[EPGC] release heap mem");
552                                         delete It->second;
553                                         DBIt->second.second.erase(It++);
554 //                                      eDebug("[EPGC] delete old event (timeMap)");
555                                 }
556                                 else
557                                         ++It;
558                         }
559                 }
560                 eDebug("[EPGC] stop cleanloop");
561                 eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
562         }
563         cleanTimer.start(CLEAN_INTERVAL,true);
564 }
565
566 eEPGCache::~eEPGCache()
567 {
568         messages.send(Message::quit);
569         kill(); // waiting for thread shutdown
570         singleLock s(cache_lock);
571         for (eventCache::iterator evIt = eventDB.begin(); evIt != eventDB.end(); evIt++)
572                 for (eventMap::iterator It = evIt->second.first.begin(); It != evIt->second.first.end(); It++)
573                         delete It->second;
574 }
575
576 void eEPGCache::gotMessage( const Message &msg )
577 {
578         switch (msg.type)
579         {
580                 case Message::flush:
581                         flushEPG(msg.service);
582                         break;
583                 case Message::startChannel:
584                 {
585                         singleLock s(channel_map_lock);
586                         channelMapIterator channel =
587                                 m_knownChannels.find(msg.channel);
588                         if ( channel != m_knownChannels.end() )
589                                 channel->second->startChannel();
590                         break;
591                 }
592                 case Message::leaveChannel:
593                 {
594                         singleLock s(channel_map_lock);
595                         channelMapIterator channel =
596                                 m_knownChannels.find(msg.channel);
597                         if ( channel != m_knownChannels.end() )
598                                 channel->second->abortEPG();
599                         break;
600                 }
601                 case Message::quit:
602                         quit(0);
603                         break;
604                 case Message::timeChanged:
605                         cleanLoop();
606                         break;
607                 default:
608                         eDebug("unhandled EPGCache Message!!");
609                         break;
610         }
611 }
612
613 void eEPGCache::thread()
614 {
615         nice(4);
616         load();
617         cleanLoop();
618         exec();
619         save();
620 }
621
622 void eEPGCache::load()
623 {
624 #if 0
625         FILE *f = fopen("/hdd/epg.dat", "r");
626         if (f)
627         {
628                 unsigned char md5_saved[16];
629                 unsigned char md5[16];
630                 int size=0;
631                 int cnt=0;
632                 bool md5ok=false;
633                 if (!md5_file("/hdd/epg.dat", 1, md5))
634                 {
635                         FILE *f = fopen("/hdd/epg.dat.md5", "r");
636                         if (f)
637                         {
638                                 fread( md5_saved, 16, 1, f);
639                                 fclose(f);
640                                 if ( !memcmp(md5_saved, md5, 16) )
641                                         md5ok=true;
642                         }
643                 }
644                 if ( md5ok )
645                 {
646                         char text1[13];
647                         fread( text1, 13, 1, f);
648                         if ( !strncmp( text1, "ENIGMA_EPG_V4", 13) )
649                         {
650                                 fread( &size, sizeof(int), 1, f);
651                                 while(size--)
652                                 {
653                                         uniqueEPGKey key;
654                                         eventMap evMap;
655                                         timeMap tmMap;
656                                         int size=0;
657                                         fread( &key, sizeof(uniqueEPGKey), 1, f);
658                                         fread( &size, sizeof(int), 1, f);
659                                         while(size--)
660                                         {
661                                                 __u8 len=0;
662                                                 __u8 type=0;
663                                                 eventData *event=0;
664                                                 fread( &type, sizeof(__u8), 1, f);
665                                                 fread( &len, sizeof(__u8), 1, f);
666                                                 event = new eventData(0, len, type);
667                                                 event->EITdata = new __u8[len];
668                                                 eventData::CacheSize+=len;
669                                                 fread( event->EITdata, len, 1, f);
670                                                 evMap[ event->getEventID() ]=event;
671                                                 tmMap[ event->getStartTime() ]=event;
672                                                 ++cnt;
673                                         }
674                                         eventDB[key]=std::pair<eventMap,timeMap>(evMap,tmMap);
675                                 }
676                                 eventData::load(f);
677                                 eDebug("%d events read from /hdd/epg.dat", cnt);
678                         }
679                         else
680                                 eDebug("[EPGC] don't read old epg database");
681                         fclose(f);
682                 }
683         }
684 #endif
685 }
686
687 void eEPGCache::save()
688 {
689 #if 0
690         struct statfs s;
691         off64_t tmp;
692         if (statfs("/hdd", &s)<0)
693                 tmp=0;
694         else
695         {
696                 tmp=s.f_blocks;
697                 tmp*=s.f_bsize;
698         }
699
700         // prevent writes to builtin flash
701         if ( tmp < 1024*1024*50 ) // storage size < 50MB
702                 return;
703
704         // check for enough free space on storage
705         tmp=s.f_bfree;
706         tmp*=s.f_bsize;
707         if ( tmp < (eventData::CacheSize*12)/10 ) // 20% overhead
708                 return;
709
710         FILE *f = fopen("/hdd/epg.dat", "w");
711         int cnt=0;
712         if ( f )
713         {
714                 const char *text = "ENIGMA_EPG_V4";
715                 fwrite( text, 13, 1, f );
716                 int size = eventDB.size();
717                 fwrite( &size, sizeof(int), 1, f );
718                 for (eventCache::iterator service_it(eventDB.begin()); service_it != eventDB.end(); ++service_it)
719                 {
720                         timeMap &timemap = service_it->second.second;
721                         fwrite( &service_it->first, sizeof(uniqueEPGKey), 1, f);
722                         size = timemap.size();
723                         fwrite( &size, sizeof(int), 1, f);
724                         for (timeMap::iterator time_it(timemap.begin()); time_it != timemap.end(); ++time_it)
725                         {
726                                 __u8 len = time_it->second->ByteSize;
727                                 fwrite( &time_it->second->type, sizeof(__u8), 1, f );
728                                 fwrite( &len, sizeof(__u8), 1, f);
729                                 fwrite( time_it->second->EITdata, len, 1, f);
730                                 ++cnt;
731                         }
732                 }
733                 eDebug("%d events written to /hdd/epg.dat", cnt);
734                 eventData::save(f);
735                 fclose(f);
736                 unsigned char md5[16];
737                 if (!md5_file("/hdd/epg.dat", 1, md5))
738                 {
739                         FILE *f = fopen("/hdd/epg.dat.md5", "w");
740                         if (f)
741                         {
742                                 fwrite( md5, 16, 1, f);
743                                 fclose(f);
744                         }
745                 }
746         }
747 #endif
748 }
749
750 eEPGCache::channel_data::channel_data(eEPGCache *ml)
751         :cache(ml)
752         ,abortTimer(ml), zapTimer(ml)
753         ,state(0), isRunning(0), haveData(0), can_delete(1)
754 {
755         CONNECT(zapTimer.timeout, eEPGCache::channel_data::startEPG);
756         CONNECT(abortTimer.timeout, eEPGCache::channel_data::abortNonAvail);
757 }
758
759 bool eEPGCache::channel_data::finishEPG()
760 {
761         if (!isRunning)  // epg ready
762         {
763                 eDebug("[EPGC] stop caching events(%d)", time(0)+eDVBLocalTimeHandler::getInstance()->difference());
764                 zapTimer.start(UPDATE_INTERVAL, 1);
765                 eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000);
766                 for (int i=0; i < 3; ++i)
767                 {
768                         seenSections[i].clear();
769                         calcedSections[i].clear();
770                 }
771                 singleLock l(cache->cache_lock);
772                 cache->channelLastUpdated[channel->getChannelID()] = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
773                 can_delete=1;
774                 return true;
775         }
776         return false;
777 }
778
779 void eEPGCache::channel_data::startEPG()
780 {
781         eDebug("[EPGC] start caching events(%d)", eDVBLocalTimeHandler::getInstance()->difference()+time(0));
782         state=0;
783         haveData=0;
784         can_delete=0;
785         for (int i=0; i < 3; ++i)
786         {
787                 seenSections[i].clear();
788                 calcedSections[i].clear();
789         }
790
791         eDVBSectionFilterMask mask;
792         memset(&mask, 0, sizeof(mask));
793         mask.pid = 0x12;
794         mask.flags = eDVBSectionFilterMask::rfCRC;
795
796         mask.data[0] = 0x4E;
797         mask.mask[0] = 0xFE;
798         m_NowNextReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_NowNextConn);
799         m_NowNextReader->start(mask);
800         isRunning |= NOWNEXT;
801
802         mask.data[0] = 0x50;
803         mask.mask[0] = 0xF0;
804         m_ScheduleReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_ScheduleConn);
805         m_ScheduleReader->start(mask);
806         isRunning |= SCHEDULE;
807
808         mask.data[0] = 0x60;
809         mask.mask[0] = 0xF0;
810         m_ScheduleOtherReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_ScheduleOtherConn);
811         m_ScheduleOtherReader->start(mask);
812         isRunning |= SCHEDULE_OTHER;
813
814         abortTimer.start(7000,true);
815 }
816
817 void eEPGCache::channel_data::abortNonAvail()
818 {
819         if (!state)
820         {
821                 if ( !(haveData&eEPGCache::NOWNEXT) && (isRunning&eEPGCache::NOWNEXT) )
822                 {
823                         eDebug("[EPGC] abort non avail nownext reading");
824                         isRunning &= ~eEPGCache::NOWNEXT;
825                         m_NowNextReader->stop();
826                         m_NowNextConn=0;
827                 }
828                 if ( !(haveData&eEPGCache::SCHEDULE) && (isRunning&eEPGCache::SCHEDULE) )
829                 {
830                         eDebug("[EPGC] abort non avail schedule reading");
831                         isRunning &= ~SCHEDULE;
832                         m_ScheduleReader->stop();
833                         m_ScheduleConn=0;
834                 }
835                 if ( !(haveData&eEPGCache::SCHEDULE_OTHER) && (isRunning&eEPGCache::SCHEDULE_OTHER) )
836                 {
837                         eDebug("[EPGC] abort non avail schedule_other reading");
838                         isRunning &= ~SCHEDULE_OTHER;
839                         m_ScheduleOtherReader->stop();
840                         m_ScheduleOtherConn=0;
841                 }
842                 if ( isRunning )
843                         abortTimer.start(90000, true);
844                 else
845                 {
846                         ++state;
847                         for (int i=0; i < 3; ++i)
848                         {
849                                 seenSections[i].clear();
850                                 calcedSections[i].clear();
851                         }
852                         can_delete=1;
853                 }
854         }
855         ++state;
856 }
857
858 void eEPGCache::channel_data::startChannel()
859 {
860         updateMap::iterator It = cache->channelLastUpdated.find( channel->getChannelID() );
861
862         int update = ( It != cache->channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (time(0)+eDVBLocalTimeHandler::getInstance()->difference()-It->second) * 1000 ) ) : ZAP_DELAY );
863
864         if (update < ZAP_DELAY)
865                 update = ZAP_DELAY;
866
867         zapTimer.start(update, 1);
868         if (update >= 60000)
869                 eDebug("[EPGC] next update in %i min", update/60000);
870         else if (update >= 1000)
871                 eDebug("[EPGC] next update in %i sec", update/1000);
872 }
873
874 void eEPGCache::channel_data::abortEPG()
875 {
876         for (int i=0; i < 3; ++i)
877         {
878                 seenSections[i].clear();
879                 calcedSections[i].clear();
880         }
881         abortTimer.stop();
882         zapTimer.stop();
883         if (isRunning)
884         {
885                 eDebug("[EPGC] abort caching events !!");
886                 if (isRunning & eEPGCache::SCHEDULE)
887                 {
888                         isRunning &= ~eEPGCache::SCHEDULE;
889                         m_ScheduleReader->stop();
890                         m_ScheduleConn=0;
891                 }
892                 if (isRunning & eEPGCache::NOWNEXT)
893                 {
894                         isRunning &= ~eEPGCache::NOWNEXT;
895                         m_NowNextReader->stop();
896                         m_NowNextConn=0;
897                 }
898                 if (isRunning & SCHEDULE_OTHER)
899                 {
900                         isRunning &= ~eEPGCache::SCHEDULE_OTHER;
901                         m_ScheduleOtherReader->stop();
902                         m_ScheduleOtherConn=0;
903                 }
904                 can_delete=1;
905         }
906 }
907
908 void eEPGCache::channel_data::readData( const __u8 *data)
909 {
910         if (!data)
911                 eDebug("get Null pointer from section reader !!");
912         else
913         {
914                 int source;
915                 int map;
916                 iDVBSectionReader *reader=NULL;
917                 switch(data[0])
918                 {
919                         case 0x4E ... 0x4F:
920                                 reader=m_NowNextReader;
921                                 source=eEPGCache::NOWNEXT;
922                                 map=0;
923                                 break;
924                         case 0x50 ... 0x5F:
925                                 reader=m_ScheduleReader;
926                                 source=eEPGCache::SCHEDULE;
927                                 map=1;
928                                 break;
929                         case 0x60 ... 0x6F:
930                                 reader=m_ScheduleOtherReader;
931                                 source=eEPGCache::SCHEDULE_OTHER;
932                                 map=2;
933                                 break;
934                         default:
935                                 eDebug("[EPGC] unknown table_id !!!");
936                                 return;
937                 }
938                 tidMap &seenSections = this->seenSections[map];
939                 tidMap &calcedSections = this->calcedSections[map];
940                 if ( state == 1 && calcedSections == seenSections || state > 1 )
941                 {
942                         eDebugNoNewLine("[EPGC] ");
943                         switch (source)
944                         {
945                                 case eEPGCache::NOWNEXT:
946                                         m_NowNextConn=0;
947                                         eDebugNoNewLine("nownext");
948                                         break;
949                                 case eEPGCache::SCHEDULE:
950                                         m_ScheduleConn=0;
951                                         eDebugNoNewLine("schedule");
952                                         break;
953                                 case eEPGCache::SCHEDULE_OTHER:
954                                         m_ScheduleOtherConn=0;
955                                         eDebugNoNewLine("schedule other");
956                                         break;
957                                 default: eDebugNoNewLine("unknown");break;
958                         }
959                         eDebug(" finished(%d)", time(0)+eDVBLocalTimeHandler::getInstance()->difference());
960                         if ( reader )
961                                 reader->stop();
962                         isRunning &= ~source;
963                         if (!isRunning)
964                                 finishEPG();
965                 }
966                 else
967                 {
968                         eit_t *eit = (eit_t*) data;
969                         __u32 sectionNo = data[0] << 24;
970                         sectionNo |= data[3] << 16;
971                         sectionNo |= data[4] << 8;
972                         sectionNo |= eit->section_number;
973
974                         tidMap::iterator it =
975                                 seenSections.find(sectionNo);
976
977                         if ( it == seenSections.end() )
978                         {
979                                 seenSections.insert(sectionNo);
980                                 calcedSections.insert(sectionNo);
981                                 __u32 tmpval = sectionNo & 0xFFFFFF00;
982                                 __u8 incr = source == NOWNEXT ? 1 : 8;
983                                 for ( int i = 0; i <= eit->last_section_number; i+=incr )
984                                 {
985                                         if ( i == eit->section_number )
986                                         {
987                                                 for (int x=i; x <= eit->segment_last_section_number; ++x)
988                                                         calcedSections.insert(tmpval|(x&0xFF));
989                                         }
990                                         else
991                                                 calcedSections.insert(tmpval|(i&0xFF));
992                                 }
993                                 cache->sectionRead(data, source, this);
994                         }
995                 }
996         }
997 }
998
999 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result )
1000 // if t == 0 we search the current event...
1001 {
1002         singleLock s(cache_lock);
1003         uniqueEPGKey key(service);
1004
1005         // check if EPG for this service is ready...
1006         eventCache::iterator It = eventDB.find( key );
1007         if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached ?
1008         {
1009                 if (!t)
1010                         t = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
1011                 timeMap::iterator i = It->second.second.lower_bound(t);  // find > or equal
1012                 if ( i != It->second.second.end() )
1013                 {
1014                         if ( i->second->getStartTime() != t )
1015                         {
1016                                 timeMap::iterator x = i;
1017                                 --x;
1018                                 if ( x != It->second.second.end() )
1019                                 {
1020                                         time_t start_time = x->second->getStartTime();
1021                                         if (t < start_time)
1022                                                 return -1;
1023                                         if (t > (start_time+x->second->getDuration()))
1024                                                 return -1;
1025                                         i = x;
1026                                 }
1027                                 else
1028                                         return -1;
1029                         }
1030                         result = i->second;
1031                         return 0;
1032                 }
1033         }
1034         return -1;
1035 }
1036
1037 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eit_event_struct *&result )
1038 {
1039         singleLock s(cache_lock);
1040         const eventData *data=0;
1041         RESULT ret = lookupEventTime(service, t, data);
1042         if ( !ret && data )
1043                 result = data->get();
1044         return ret;
1045 }
1046
1047 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, Event *& result )
1048 {
1049         singleLock s(cache_lock);
1050         const eventData *data=0;
1051         RESULT ret = lookupEventTime(service, t, data);
1052         if ( !ret && data )
1053                 result = new Event((uint8_t*)data->get());
1054         return ret;
1055 }
1056
1057 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, ePtr<eServiceEvent> &result )
1058 {
1059         singleLock s(cache_lock);
1060         const eventData *data=0;
1061         RESULT ret = lookupEventTime(service, t, data);
1062         if ( !ret && data )
1063         {
1064                 Event ev((uint8_t*)data->get());
1065                 result = new eServiceEvent();
1066                 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
1067                 ret = result->parseFrom(&ev, (ref.getTransportStreamID().get()<<16)|ref.getOriginalNetworkID().get());
1068         }
1069         return ret;
1070 }
1071
1072 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eventData *&result )
1073 {
1074         singleLock s(cache_lock);
1075         uniqueEPGKey key( service );
1076
1077         eventCache::iterator It = eventDB.find( key );
1078         if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached?
1079         {
1080                 eventMap::iterator i( It->second.first.find( event_id ));
1081                 if ( i != It->second.first.end() )
1082                 {
1083                         result = i->second;
1084                         return 0;
1085                 }
1086                 else
1087                 {
1088                         result = 0;
1089                         eDebug("event %04x not found in epgcache", event_id);
1090                 }
1091         }
1092         return -1;
1093 }
1094
1095 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eit_event_struct *&result)
1096 {
1097         singleLock s(cache_lock);
1098         const eventData *data=0;
1099         RESULT ret = lookupEventId(service, event_id, data);
1100         if ( !ret && data )
1101                 result = data->get();
1102         return ret;
1103 }
1104
1105 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, Event *& result)
1106 {
1107         singleLock s(cache_lock);
1108         const eventData *data=0;
1109         RESULT ret = lookupEventId(service, event_id, data);
1110         if ( !ret && data )
1111                 result = new Event((uint8_t*)data->get());
1112         return ret;
1113 }
1114
1115 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, ePtr<eServiceEvent> &result)
1116 {
1117         singleLock s(cache_lock);
1118         const eventData *data=0;
1119         RESULT ret = lookupEventId(service, event_id, data);
1120         if ( !ret && data )
1121         {
1122                 Event ev((uint8_t*)data->get());
1123                 result = new eServiceEvent();
1124                 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
1125                 ret = result->parseFrom(&ev, (ref.getTransportStreamID().get()<<16)|ref.getOriginalNetworkID().get());
1126         }
1127         return ret;
1128 }
1129
1130 RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, int minutes)
1131 {
1132         eventCache::iterator It = eventDB.find( service );
1133         if ( It != eventDB.end() && It->second.second.size() )
1134         {
1135                 m_timemap_end = minutes != -1 ? It->second.second.upper_bound(begin+minutes*60) : It->second.second.end();
1136                 if ( begin != -1 )
1137                 {
1138                         m_timemap_cursor = It->second.second.lower_bound(begin);
1139                         if ( m_timemap_cursor != It->second.second.end() && m_timemap_cursor != It->second.second.begin() )
1140                         {
1141                                 timeMap::iterator it = m_timemap_cursor;
1142                                 --it;
1143                                 if ( (it->second->getStartTime() + it->second->getDuration()) > begin )
1144                                         m_timemap_cursor = it;
1145                         }
1146                 }
1147                 else
1148                         m_timemap_cursor = It->second.second.begin();
1149                 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
1150                 currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get();
1151                 return 0;
1152         }
1153         return -1;
1154 }
1155
1156 RESULT eEPGCache::getNextTimeEntry(const eventData *& result)
1157 {
1158         if ( m_timemap_cursor != m_timemap_end )
1159         {
1160                 result = m_timemap_cursor++->second;
1161                 return 0;
1162         }
1163         return -1;
1164 }
1165
1166 RESULT eEPGCache::getNextTimeEntry(const eit_event_struct *&result)
1167 {
1168         if ( m_timemap_cursor != m_timemap_end )
1169         {
1170                 result = m_timemap_cursor++->second->get();
1171                 return 0;
1172         }
1173         return -1;
1174 }
1175
1176 RESULT eEPGCache::getNextTimeEntry(Event *&result)
1177 {
1178         if ( m_timemap_cursor != m_timemap_end )
1179         {
1180                 result = new Event((uint8_t*)m_timemap_cursor++->second->get());
1181                 return 0;
1182         }
1183         return -1;
1184 }
1185
1186 RESULT eEPGCache::getNextTimeEntry(ePtr<eServiceEvent> &result)
1187 {
1188         if ( m_timemap_cursor != m_timemap_end )
1189         {
1190                 Event ev((uint8_t*)m_timemap_cursor++->second->get());
1191                 result = new eServiceEvent();
1192                 return result->parseFrom(&ev, currentQueryTsidOnid);
1193         }
1194         return -1;
1195 }