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