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