1 #include <lib/dvb/epgcache.h>
2 #include <lib/dvb/dvb.h>
3 #include <lib/dvb/lowlevel/eit.h>
8 #include <lib/service/event.h>
14 #include <unistd.h> // for usleep
15 #include <sys/vfs.h> // for statfs
16 #include <lib/base/eerror.h>
17 #include <lib/base/encoding.h>
18 #include <lib/base/estring.h>
19 #include <lib/dvb/pmt.h>
20 #include <lib/dvb/db.h>
21 #include <lib/python/python.h>
22 #include <dvbsi++/descriptor_tag.h>
24 /* Interval between "garbage collect" cycles */
25 #define CLEAN_INTERVAL 60000 // 1 min
26 /* Restart EPG data capture */
27 #define UPDATE_INTERVAL 3600000 // 60 min
28 /* Time to wait after tuning in before EPG data capturing starts */
29 #define ZAP_DELAY 2000 // 2 sec
37 DescriptorPair(int c, uint8_t* d): reference_count(c), data(d) {}
40 typedef std::tr1::unordered_map<uint32_t, DescriptorPair> DescriptorMap;
44 uint8_t rawEITdata[10];
48 static DescriptorMap descriptors;
49 static uint8_t data[];
50 static unsigned int CacheSize;
51 static bool isCacheCorrupt;
52 eventData(const eit_event_struct* e = NULL, int size = 0, int type = 0, int tsidonid = 0);
54 static void load(FILE *);
55 static void save(FILE *);
56 static void cacheCorrupt(const char* context);
57 const eit_event_struct* get() const;
58 int getEventID() const
60 return (rawEITdata[0] << 8) | rawEITdata[1];
62 time_t getStartTime() const
64 return parseDVBtime(&rawEITdata[2]);
66 int getDuration() const
68 return fromBCD(rawEITdata[7])*3600+fromBCD(rawEITdata[8])*60+fromBCD(rawEITdata[9]);
72 unsigned int eventData::CacheSize = 0;
73 bool eventData::isCacheCorrupt = 0;
74 DescriptorMap eventData::descriptors;
75 uint8_t eventData::data[2 * 4096 + 12];
76 extern const uint32_t crc32_table[256];
78 const eServiceReference &handleGroup(const eServiceReference &ref)
80 if (ref.flags & eServiceReference::isGroup)
82 ePtr<eDVBResourceManager> res;
83 if (!eDVBResourceManager::getInstance(res))
85 ePtr<iDVBChannelList> db;
86 if (!res->getChannelList(db))
88 eBouquet *bouquet = NULL;
89 if (!db->getBouquet(ref, bouquet))
91 std::list<eServiceReference>::iterator it(bouquet->m_services.begin());
92 if (it != bouquet->m_services.end())
101 static uint32_t calculate_crc_hash(const uint8_t *data, int size)
104 for (int i = 0; i < size; ++i)
105 crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ data[i]) & 0xFF];
109 eventData::eventData(const eit_event_struct* e, int size, int _type, int tsidonid)
110 :n_crc(0), type(_type & 0xFF), crc_list(NULL)
113 return; /* Used when loading from file */
116 uint32_t *pdescr=descr;
118 uint8_t *data = (uint8_t*)e;
124 uint8_t *descr = data + ptr;
125 int descr_len = descr[1];
127 if (size >= descr_len)
131 case EXTENDED_EVENT_DESCRIPTOR:
132 case LINKAGE_DESCRIPTOR:
133 case COMPONENT_DESCRIPTOR:
134 case CONTENT_DESCRIPTOR:
135 case PARENTAL_RATING_DESCRIPTOR:
138 uint32_t crc = calculate_crc_hash(descr, descr_len);
139 DescriptorMap::iterator it = descriptors.find(crc);
140 if ( it == descriptors.end() )
142 CacheSize+=descr_len;
143 uint8_t *d = new uint8_t[descr_len];
144 memcpy(d, descr, descr_len);
145 descriptors[crc] = DescriptorPair(1, d);
148 ++it->second.reference_count;
152 case SHORT_EVENT_DESCRIPTOR:
154 //parse the data out from the short event descriptor
155 //get the country code, which will be used for converting to UTF8
156 std::string cc( (const char*)&descr[2], 3);
157 std::transform(cc.begin(), cc.end(), cc.begin(), tolower);
158 int table = encodingHandler.getCountryCodeDefaultMapping(cc);
160 int eventNameLen = descr[5];
161 int eventTextLen = descr[6 + eventNameLen];
163 //convert our strings to UTF8
164 std::string eventNameUTF8 = convertDVBUTF8((const unsigned char*)&descr[6], eventNameLen, table, tsidonid);
165 std::string textUTF8 = convertDVBUTF8((const unsigned char*)&descr[7 + eventNameLen], eventTextLen, table, tsidonid);
166 unsigned int eventNameUTF8len = eventNameUTF8.length();
167 unsigned int textUTF8len = textUTF8.length();
169 //Rebuild the short event descriptor with UTF-8 strings
171 //Save the title first
172 if( eventNameUTF8len > 0 ) //only store the data if there is something to store
174 /*this will actually cause us to save some memory
175 previously some descriptors didnt match because there text was different and titles the same.
176 Now that we store them seperatly we can save some space on title data some rough calculation show anywhere from 20 - 40% savings
178 eventNameUTF8len = truncateUTF8(eventNameUTF8, 255 - 6);
179 int title_len = 6 + eventNameUTF8len;
180 uint8_t *title_data = new uint8_t[title_len + 2];
181 title_data[0] = SHORT_EVENT_DESCRIPTOR;
182 title_data[1] = title_len;
183 title_data[2] = descr[2];
184 title_data[3] = descr[3];
185 title_data[4] = descr[4];
186 title_data[5] = eventNameUTF8len + 1;
187 title_data[6] = 0x15; //identify event name as UTF-8
188 memcpy(&title_data[7], eventNameUTF8.data(), eventNameUTF8len);
189 title_data[7 + eventNameUTF8len] = 0;
191 //Calculate the CRC, based on our new data
192 title_len += 2; //add 2 the length to include the 2 bytes in the header
193 uint32_t title_crc = calculate_crc_hash(title_data, title_len);
195 DescriptorMap::iterator it = descriptors.find(title_crc);
196 if ( it == descriptors.end() )
198 CacheSize += title_len;
199 descriptors[title_crc] = DescriptorPair(1, title_data);
203 ++it->second.reference_count;
204 delete [] title_data;
206 *pdescr++ = title_crc;
210 if( textUTF8len > 0 ) //only store the data if there is something to store
212 textUTF8len = truncateUTF8(textUTF8, 255 - 6);
213 int text_len = 6 + textUTF8len;
214 uint8_t *text_data = new uint8_t[text_len + 2];
215 text_data[0] = SHORT_EVENT_DESCRIPTOR;
216 text_data[1] = text_len;
217 text_data[2] = descr[2];
218 text_data[3] = descr[3];
219 text_data[4] = descr[4];
221 text_data[6] = textUTF8len + 1; //identify text as UTF-8
222 text_data[7] = 0x15; //identify text as UTF-8
223 memcpy(&text_data[8], textUTF8.data(), textUTF8len);
225 text_len += 2; //add 2 the length to include the 2 bytes in the header
226 uint32_t text_crc = calculate_crc_hash(text_data, text_len);
228 DescriptorMap::iterator it = descriptors.find(text_crc);
229 if ( it == descriptors.end() )
231 CacheSize += text_len;
232 descriptors[text_crc] = DescriptorPair(1, text_data);
236 ++it->second.reference_count;
239 *pdescr++ = text_crc;
243 default: // do not cache all other descriptors
252 memcpy(rawEITdata, (uint8_t*)e, 10);
253 ASSERT(pdescr <= &descr[65]);
254 n_crc = pdescr - descr;
257 crc_list = new uint32_t[n_crc];
258 memcpy(crc_list, descr, n_crc * sizeof(uint32_t));
260 CacheSize += sizeof(*this) + n_crc * sizeof(uint32_t);
263 const eit_event_struct* eventData::get() const
265 unsigned int pos = 12;
266 memcpy(data, rawEITdata, 10);
267 unsigned int descriptors_length = 0;
268 for (uint8_t i = 0; i < n_crc; ++i)
270 DescriptorMap::iterator it = descriptors.find(crc_list[i]);
271 if (it != descriptors.end())
273 unsigned int b = it->second.data[1] + 2;
274 if (pos + b < sizeof(data))
276 memcpy(data + pos, it->second.data, b);
278 descriptors_length += b;
282 cacheCorrupt("eventData::get");
284 data[10] = (descriptors_length >> 8) & 0x0F;
285 data[11] = descriptors_length & 0xFF;
286 return (eit_event_struct*)data;
289 eventData::~eventData()
291 for ( uint8_t i = 0; i < n_crc; ++i )
293 DescriptorMap::iterator it = descriptors.find(crc_list[i]);
294 if ( it != descriptors.end() )
296 DescriptorPair &p = it->second;
297 if (!--p.reference_count) // no more used descriptor
299 CacheSize -= it->second.data[1];
300 delete [] it->second.data; // free descriptor memory
301 descriptors.erase(it); // remove entry from descriptor map
306 cacheCorrupt("eventData::~eventData");
310 CacheSize -= sizeof(*this) + n_crc * sizeof(uint32_t);
313 void eventData::load(FILE *f)
319 fread(&size, sizeof(int), 1, f);
320 descriptors.rehash(size);
323 fread(&id, sizeof(uint32_t), 1, f);
324 fread(&p.reference_count, sizeof(int), 1, f);
325 fread(header, 2, 1, f);
326 int bytes = header[1]+2;
327 p.data = new uint8_t[bytes];
328 p.data[0] = header[0];
329 p.data[1] = header[1];
330 fread(p.data+2, bytes-2, 1, f);
336 void eventData::save(FILE *f)
340 int size=descriptors.size();
341 DescriptorMap::iterator it(descriptors.begin());
342 fwrite(&size, sizeof(int), 1, f);
345 fwrite(&it->first, sizeof(uint32_t), 1, f);
346 fwrite(&it->second.reference_count, sizeof(int), 1, f);
347 fwrite(it->second.data, it->second.data[1]+2, 1, f);
353 void eventData::cacheCorrupt(const char* context)
356 eDebug("[eventData] EPG Cache is corrupt (%s), you should restart Enigma!", context);
359 isCacheCorrupt = true;
360 if (!eEPGCache::instance->m_filename.empty())
361 unlink(eEPGCache::instance->m_filename.c_str()); // Remove corrupt EPG data
365 eEPGCache* eEPGCache::instance;
366 static pthread_mutex_t cache_lock =
367 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
368 static pthread_mutex_t channel_map_lock =
369 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
371 DEFINE_REF(eEPGCache)
373 eEPGCache::eEPGCache()
374 :messages(this,1), cleanTimer(eTimer::create(this)), m_running(false)
376 eDebug("[eEPGCache] Initialized EPGCache (wait for setCacheFile call now)");
381 CONNECT(messages.recv_msg, eEPGCache::gotMessage);
382 CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated);
383 CONNECT(cleanTimer->timeout, eEPGCache::cleanLoop);
385 ePtr<eDVBResourceManager> res_mgr;
386 eDVBResourceManager::getInstance(res_mgr);
388 eDebug("[eEPGCache] no resource manager !!!!!!!");
390 res_mgr->connectChannelAdded(slot(*this,&eEPGCache::DVBChannelAdded), m_chanAddedConn);
395 void eEPGCache::setCacheFile(const char *path)
397 bool inited = !m_filename.empty();
401 eDebug("[eEPGCache] setCacheFile read/write epg data from/to '%s'", m_filename.c_str());
402 if (eDVBLocalTimeHandler::getInstance()->ready())
407 void eEPGCache::timeUpdated()
409 if (!m_filename.empty())
413 eDebug("[eEPGCache] time updated.. start EPG Mainloop");
416 singleLock s(channel_map_lock);
417 for (ChannelMap::const_iterator it = m_knownChannels.begin(); it != m_knownChannels.end(); ++it)
419 if (it->second->state == -1) {
421 messages.send(Message(Message::startChannel, it->first));
425 messages.send(Message(Message::timeChanged));
428 eDebug("[eEPGCache] time updated.. but cache file not set yet.. dont start epg!!");
431 void eEPGCache::DVBChannelAdded(eDVBChannel *chan)
435 // eDebug("[eEPGCache] add channel %p", chan);
436 channel_data *data = new channel_data(this);
437 data->channel = chan;
438 data->prevChannelState = -1;
439 #ifdef ENABLE_PRIVATE_EPG
440 data->m_PrivatePid = -1;
442 #ifdef ENABLE_MHW_EPG
443 data->m_mhw2_channel_pid = 0x231; // defaults for astra 19.2 D+
444 data->m_mhw2_title_pid = 0x234; // defaults for astra 19.2 D+
445 data->m_mhw2_summary_pid = 0x236; // defaults for astra 19.2 D+
447 singleLock s(channel_map_lock);
448 m_knownChannels.insert( std::pair<iDVBChannel*, channel_data* >(chan, data) );
449 chan->connectStateChange(slot(*this, &eEPGCache::DVBChannelStateChanged), data->m_stateChangedConn);
453 void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
455 ChannelMap::const_iterator it = m_knownChannels.find(chan);
456 if ( it == m_knownChannels.end() )
457 eDebug("[eEPGCache] will start non existing channel %p !!!", chan);
460 channel_data &data = *it->second;
461 ePtr<eDVBResourceManager> res_mgr;
462 if ( eDVBResourceManager::getInstance( res_mgr ) )
463 eDebug("[eEPGCache] no res manager!!");
466 ePtr<iDVBDemux> demux;
467 if ( data.channel->getDemux(demux, 0) )
469 eDebug("[eEPGCache] no demux!!");
474 RESULT res = demux->createSectionReader( this, data.m_NowNextReader );
477 eDebug("[eEPGCache] couldnt initialize nownext reader!!");
481 res = demux->createSectionReader( this, data.m_ScheduleReader );
484 eDebug("[eEPGCache] couldnt initialize schedule reader!!");
488 res = demux->createSectionReader( this, data.m_ScheduleOtherReader );
491 eDebug("[eEPGCache] couldnt initialize schedule other reader!!");
496 res = demux->createSectionReader( this, data.m_VirginNowNextReader );
499 eDebug("[eEPGCache] couldnt initialize virgin nownext reader!!");
503 res = demux->createSectionReader( this, data.m_VirginScheduleReader );
506 eDebug("[eEPGCache] couldnt initialize virgin schedule reader!!");
511 res = demux->createSectionReader( this, data.m_NetmedScheduleReader );
514 eDebug("[eEPGCache] couldnt initialize netmed schedule reader!!");
518 res = demux->createSectionReader( this, data.m_NetmedScheduleOtherReader );
521 eDebug("[eEPGCache] couldnt initialize netmed schedule other reader!!");
525 res = demux->createSectionReader( this, data.m_ViasatReader );
528 eDebug("[eEPGCache] couldnt initialize viasat reader!!");
531 #ifdef ENABLE_PRIVATE_EPG
532 res = demux->createSectionReader( this, data.m_PrivateReader );
535 eDebug("[eEPGCache] couldnt initialize private reader!!");
539 #ifdef ENABLE_MHW_EPG
540 res = demux->createSectionReader( this, data.m_MHWReader );
543 eDebug("[eEPGCache] couldnt initialize mhw reader!!");
546 res = demux->createSectionReader( this, data.m_MHWReader2 );
549 eDebug("[eEPGCache] couldnt initialize mhw reader!!");
554 res = demux->createSectionReader( this, data.m_FreeSatScheduleOtherReader );
557 eDebug("[eEPGCache] couldnt initialize FreeSat reader!!");
560 res = demux->createSectionReader( this, data.m_FreeSatScheduleOtherReader2 );
563 eDebug("[eEPGCache] couldnt initialize FreeSat reader 2!!");
570 messages.send(Message(Message::startChannel, chan));
571 // -> gotMessage -> changedService
580 void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan)
582 ChannelMap::iterator it = m_knownChannels.find(chan);
583 if ( it != m_knownChannels.end() )
586 chan->getState(state);
587 if ( it->second->prevChannelState != state )
591 case iDVBChannel::state_ok:
593 eDebug("[eEPGCache] channel %p running", chan);
594 DVBChannelRunning(chan);
597 case iDVBChannel::state_release:
599 eDebug("[eEPGCache] remove channel %p", chan);
600 if (it->second->state >= 0)
601 messages.send(Message(Message::leaveChannel, chan));
602 channel_data* cd = it->second;
603 pthread_mutex_lock(&cd->channel_active);
605 singleLock s(channel_map_lock);
606 m_knownChannels.erase(it);
608 pthread_mutex_unlock(&cd->channel_active);
610 // -> gotMessage -> abortEPG
613 default: // ignore all other events
617 it->second->prevChannelState = state;
622 bool eEPGCache::FixOverlapping(EventCacheItem &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service)
625 timeMap::iterator tmp = tm_it;
626 while ((tmp->first + tmp->second->getDuration() - 300) > TM)
629 #ifdef ENABLE_PRIVATE_EPG
630 && tmp->second->type != PRIVATE
632 #ifdef ENABLE_MHW_EPG
633 && tmp->second->type != MHW
637 uint16_t event_id = tmp->second->getEventID();
638 servicemap.byEvent.erase(event_id);
640 Event evt((uint8_t*)tmp->second->get());
642 event.parseFrom(&evt, service.sid<<16|service.onid);
643 eDebug("[eEPGCache] (1)erase no more used event %04x %d\n%s %s\n%s",
644 service.sid, event_id,
645 event.getBeginTimeString().c_str(),
646 event.getEventName().c_str(),
647 event.getExtendedDescription().c_str());
650 if (tmp == servicemap.byTime.begin())
652 servicemap.byTime.erase(tmp);
656 servicemap.byTime.erase(tmp--);
661 if (tmp == servicemap.byTime.begin())
668 while(tmp->first < (TM+duration-300))
670 if (tmp->first != TM && tmp->second->type != PRIVATE)
672 uint16_t event_id = tmp->second->getEventID();
673 servicemap.byEvent.erase(event_id);
675 Event evt((uint8_t*)tmp->second->get());
677 event.parseFrom(&evt, service.sid<<16|service.onid);
678 eDebug("[eEPGCache] (2)erase no more used event %04x %d\n%s %s\n%s",
679 service.sid, event_id,
680 event.getBeginTimeString().c_str(),
681 event.getEventName().c_str(),
682 event.getExtendedDescription().c_str());
685 servicemap.byTime.erase(tmp++);
690 if (tmp == servicemap.byTime.end())
696 void eEPGCache::sectionRead(const uint8_t *data, int source, channel_data *channel)
698 const eit_t *eit = (const eit_t*) data;
700 int len = eit->getSectionLength()-1;//+3-4;
707 * disable for now, as this hack breaks EIT parsing for
708 * services with a low segment_last_table_id
710 * Multichoice should be the exception, not the rule...
713 // This fixed the EPG on the Multichoice irdeto systems
714 // the EIT packet is non-compliant.. their EIT packet stinks
715 if ( data[ptr-1] < 0x40 )
719 int onid = eit->getOriginalNetworkId();
720 int tsid = eit->getTransportStreamId();
722 // Cablecom HACK .. tsid / onid in eit data are incorrect.. so we use
723 // it from running channel (just for current transport stream eit data)
725 * Make an exception for BEV (onid 0x100, 0x101), which doesn't use
726 * SCHEDULE_OTHER. As a result SCHEDULE will contain data for different tsid's,
727 * so we should not replace it with the current tsid.
729 bool use_transponder_chid = onid != 0x101 && onid != 0x100 && (source == SCHEDULE || (source == NOWNEXT && data[0] == 0x4E));
731 if (use_transponder_chid && channel)
733 eDVBChannelID chid = channel->channel->getChannelID();
735 onid = chid.original_network_id.get();
736 tsid = chid.transport_stream_id.get();
739 uniqueEPGKey service( eit->getServiceID(), onid, tsid);
741 eit_event_struct* eit_event = (eit_event_struct*) (data+ptr);
745 time_t TM = parseDVBtime((const uint8_t*)eit_event + 2);
746 time_t now = ::time(0);
748 if ( TM != 3599 && TM > -1 && channel)
749 channel->haveData |= source;
751 singleLock s(cache_lock);
752 // hier wird immer eine eventMap zurck gegeben.. entweder eine vorhandene..
753 // oder eine durch [] erzeugte
754 EventCacheItem &servicemap = eventDB[service];
755 eventMap::iterator prevEventIt = servicemap.byEvent.end();
756 timeMap::iterator prevTimeIt = servicemap.byTime.end();
761 eit_event_size = eit_event->getDescriptorsLoopLength()+EIT_LOOP_SIZE;
763 duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
764 TM = parseDVBtime((const uint8_t*)eit_event + 2, &event_hash);
766 if ( (TM != 3599) && // NVOD Service
767 (now <= (TM+duration)) && // skip old events
768 (TM < (now+28*24*60*60)) && // no more than 4 weeks in future
769 ( (onid != 1714) || (duration != (24*3600-1)) ) // PlatformaHD invalid event
772 uint16_t event_id = eit_event->getEventId();
774 int ev_erase_count = 0;
775 int tm_erase_count = 0;
778 // hack for some polsat services on 13.0E..... but this also replaces other valid event_ids with value 0..
779 // but we dont care about it...
780 event_id = event_hash;
781 eit_event->event_id_hi = event_hash >> 8;
782 eit_event->event_id_lo = event_hash & 0xFF;
785 // search in eventmap
786 eventMap::iterator ev_it =
787 servicemap.byEvent.find(event_id);
789 //eDebug("[eEPGCache] event_id : %d, sid : %04x", event_id, service.sid);
791 // entry with this event_id is already exist ?
792 if ( ev_it != servicemap.byEvent.end() )
794 if ( source > ev_it->second->type ) // update needed ?
795 goto next; // when not.. then skip this entry
797 // search this event in timemap
798 timeMap::iterator tm_it_tmp =
799 servicemap.byTime.find(ev_it->second->getStartTime());
801 if ( tm_it_tmp != servicemap.byTime.end() )
803 if ( tm_it_tmp->first == TM ) // just update eventdata
806 eventData *tmp = ev_it->second;
807 ev_it->second = tm_it_tmp->second = new eventData(eit_event, eit_event_size, source, (tsid<<16)|onid);
808 if (FixOverlapping(servicemap, TM, duration, tm_it_tmp, service))
810 prevEventIt = servicemap.byEvent.end();
811 prevTimeIt = servicemap.byTime.end();
816 else // event has new event begin time
819 // delete the found record from timemap
820 servicemap.byTime.erase(tm_it_tmp);
821 prevTimeIt = servicemap.byTime.end();
826 // search in timemap, for check of a case if new time has coincided with time of other event
827 // or event was is not found in eventmap
828 timeMap::iterator tm_it =
829 servicemap.byTime.find(TM);
831 if ( tm_it != servicemap.byTime.end() )
833 // event with same start time but another event_id...
834 if ( source > tm_it->second->type &&
835 ev_it == servicemap.byEvent.end() )
836 goto next; // when not.. then skip this entry
838 // search this time in eventmap
839 eventMap::iterator ev_it_tmp = servicemap.byEvent.find(tm_it->second->getEventID());
841 if ( ev_it_tmp != servicemap.byEvent.end() )
844 // delete the found record from eventmap
845 servicemap.byEvent.erase(ev_it_tmp);
846 prevEventIt = servicemap.byEvent.end();
849 evt = new eventData(eit_event, eit_event_size, source, (tsid<<16)|onid);
851 bool consistencyCheck=true;
853 if (ev_erase_count > 0 && tm_erase_count > 0) // 2 different pairs have been removed
856 delete ev_it->second;
857 delete tm_it->second;
861 else if (ev_erase_count == 0 && tm_erase_count > 0)
864 delete ev_it->second;
865 tm_it = prevTimeIt = servicemap.byTime.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
868 else if (ev_erase_count > 0 && tm_erase_count == 0)
871 delete tm_it->second;
872 ev_it = prevEventIt = servicemap.byEvent.insert( prevEventIt, std::pair<const uint16_t, eventData*>( event_id, evt) );
875 else // added new eventData
878 consistencyCheck=false;
880 ev_it = prevEventIt = servicemap.byEvent.insert( prevEventIt, std::pair<const uint16_t, eventData*>( event_id, evt) );
881 tm_it = prevTimeIt = servicemap.byTime.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
885 if ( consistencyCheck )
887 if ( tm_it->second != evt || ev_it->second != evt )
888 eFatal("[eEPGCache] tm_it->second != ev_it->second");
889 else if ( tm_it->second->getStartTime() != tm_it->first )
890 eFatal("[eEPGCache] event start_time(%d) non equal timemap key(%d)",
891 (int)tm_it->second->getStartTime(), (int)tm_it->first );
892 else if ( tm_it->first != TM )
893 eFatal("[eEPGCache] timemap key(%d) non equal TM(%d)",
894 (int)tm_it->first, (int)TM);
895 else if ( ev_it->second->getEventID() != ev_it->first )
896 eFatal("[eEPGCache] event_id (%d) non equal event_map key(%d)",
897 (int)ev_it->second->getEventID(), (int)ev_it->first);
898 else if ( ev_it->first != event_id )
899 eFatal("[eEPGCache] eventmap key(%d) non equal event_id(%d)",
900 (int)ev_it->first, (int)event_id );
903 if (FixOverlapping(servicemap, TM, duration, tm_it, service))
905 prevEventIt = servicemap.byEvent.end();
906 prevTimeIt = servicemap.byTime.end();
911 if ( servicemap.byEvent.size() != servicemap.byTime.size() )
913 FILE *f = fopen("/hdd/event_map.txt", "w+");
915 for (eventMap::iterator it(servicemap.byEvent.begin())
916 ; it != servicemap.byEvent.end(); ++it )
917 fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n",
918 i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
920 f = fopen("/hdd/time_map.txt", "w+");
922 for (timeMap::iterator it(servicemap.byTime.begin())
923 ; it != servicemap.byTime.end(); ++it )
924 fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n",
925 i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
928 eFatal("[eEPGCache] (1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d",
929 service.sid, service.tsid, service.onid,
930 servicemap.byEvent.size(), servicemap.byTime.size() );
933 ptr += eit_event_size;
934 eit_event = (eit_event_struct*)(((uint8_t*)eit_event) + eit_event_size);
938 void eEPGCache::flushEPG(const uniqueEPGKey & s)
940 eDebug("[eEPGCache] flushEPG %d", (int)(bool)s);
941 singleLock l(cache_lock);
942 if (s) // clear only this service
944 eventCache::iterator it = eventDB.find(s);
945 if ( it != eventDB.end() )
947 eventMap &evMap = it->second.byEvent;
948 timeMap &tmMap = it->second.byTime;
950 for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
955 // TODO .. search corresponding channel for removed service and remove this channel from lastupdated map
956 #ifdef ENABLE_PRIVATE_EPG
957 contentMaps::iterator it =
958 content_time_tables.find(s);
959 if ( it != content_time_tables.end() )
962 content_time_tables.erase(it);
967 else // clear complete EPG Cache
969 for (eventCache::iterator it(eventDB.begin());
970 it != eventDB.end(); ++it)
972 eventMap &evMap = it->second.byEvent;
973 timeMap &tmMap = it->second.byTime;
974 for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
980 #ifdef ENABLE_PRIVATE_EPG
981 content_time_tables.clear();
983 channelLastUpdated.clear();
984 singleLock m(channel_map_lock);
985 for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
986 it->second->startEPG();
990 void eEPGCache::cleanLoop()
992 { /* scope for cache lock */
993 time_t now = ::time(0) - historySeconds;
994 singleLock s(cache_lock);
996 for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++)
998 bool updated = false;
999 for (timeMap::iterator It = DBIt->second.byTime.begin(); It != DBIt->second.byTime.end() && It->first < now;)
1001 if ( now > (It->first+It->second->getDuration()) ) // outdated normal entry (nvod references to)
1003 // remove entry from eventMap
1004 eventMap::iterator b(DBIt->second.byEvent.find(It->second->getEventID()));
1005 if ( b != DBIt->second.byEvent.end() )
1007 // release Heap Memory for this entry (new ....)
1008 //eDebug("[eEPGCache] delete old event (evmap)");
1009 DBIt->second.byEvent.erase(b);
1012 // remove entry from timeMap
1013 //eDebug("[eEPGCache] release heap mem");
1015 DBIt->second.byTime.erase(It++);
1016 //eDebug("[eEPGCache] delete old event (timeMap)");
1022 #ifdef ENABLE_PRIVATE_EPG
1025 contentMaps::iterator x =
1026 content_time_tables.find( DBIt->first );
1027 if ( x != content_time_tables.end() )
1029 timeMap &tmMap = DBIt->second.byTime;
1030 for ( contentMap::iterator i = x->second.begin(); i != x->second.end(); )
1032 for ( contentTimeMap::iterator it(i->second.begin());
1033 it != i->second.end(); )
1035 if ( tmMap.find(it->second.first) == tmMap.end() )
1036 i->second.erase(it++);
1040 if ( i->second.size() )
1043 x->second.erase(i++);
1049 } /* release lock */
1050 cleanTimer->start(CLEAN_INTERVAL,true);
1053 eEPGCache::~eEPGCache()
1056 messages.send(Message::quit);
1057 kill(); // waiting for thread shutdown
1058 singleLock s(cache_lock);
1059 for (eventCache::iterator evIt = eventDB.begin(); evIt != eventDB.end(); evIt++)
1060 for (eventMap::iterator It = evIt->second.byEvent.begin(); It != evIt->second.byEvent.end(); It++)
1064 void eEPGCache::gotMessage( const Message &msg )
1068 case Message::flush:
1069 flushEPG(msg.service);
1071 case Message::startChannel:
1073 singleLock s(channel_map_lock);
1074 ChannelMap::const_iterator channel = m_knownChannels.find(msg.channel);
1075 if ( channel != m_knownChannels.end() )
1076 channel->second->startChannel();
1079 case Message::leaveChannel:
1081 singleLock s(channel_map_lock);
1082 ChannelMap::const_iterator channel = m_knownChannels.find(msg.channel);
1083 if ( channel != m_knownChannels.end() )
1084 channel->second->abortEPG();
1090 #ifdef ENABLE_PRIVATE_EPG
1091 case Message::got_private_pid:
1093 singleLock s(channel_map_lock);
1094 for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
1096 eDVBChannel *channel = (eDVBChannel*) it->first;
1097 channel_data *data = it->second;
1098 eDVBChannelID chid = channel->getChannelID();
1099 if ( chid.transport_stream_id.get() == msg.service.tsid &&
1100 chid.original_network_id.get() == msg.service.onid &&
1101 data->m_PrivatePid == -1 )
1103 data->m_PrevVersion = -1;
1104 data->m_PrivatePid = msg.pid;
1105 data->m_PrivateService = msg.service;
1106 int onid = chid.original_network_id.get();
1107 onid |= 0x80000000; // we use highest bit as private epg indicator
1108 chid.original_network_id = onid;
1109 updateMap::iterator It = channelLastUpdated.find( chid );
1110 int update = ( It != channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (::time(0)-It->second) * 1000 ) ) : ZAP_DELAY );
1111 if (update < ZAP_DELAY)
1113 data->startPrivateTimer->start(update, 1);
1114 if (update >= 60000)
1115 eDebug("[eEPGCache] next private update in %i min", update/60000);
1116 else if (update >= 1000)
1117 eDebug("[eEPGCache] next private update in %i sec", update/1000);
1124 #ifdef ENABLE_MHW_EPG
1125 case Message::got_mhw2_channel_pid:
1127 singleLock s(channel_map_lock);
1128 for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
1130 eDVBChannel *channel = (eDVBChannel*) it->first;
1131 channel_data *data = it->second;
1132 eDVBChannelID chid = channel->getChannelID();
1133 if ( chid.transport_stream_id.get() == msg.service.tsid &&
1134 chid.original_network_id.get() == msg.service.onid )
1136 data->m_mhw2_channel_pid = msg.pid;
1137 eDebug("[eEPGCache] got mhw2 channel pid %04x", msg.pid);
1143 case Message::got_mhw2_title_pid:
1145 singleLock s(channel_map_lock);
1146 for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
1148 eDVBChannel *channel = (eDVBChannel*) it->first;
1149 channel_data *data = it->second;
1150 eDVBChannelID chid = channel->getChannelID();
1151 if ( chid.transport_stream_id.get() == msg.service.tsid &&
1152 chid.original_network_id.get() == msg.service.onid )
1154 data->m_mhw2_title_pid = msg.pid;
1155 eDebug("[eEPGCache] got mhw2 title pid %04x", msg.pid);
1161 case Message::got_mhw2_summary_pid:
1163 singleLock s(channel_map_lock);
1164 for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
1166 eDVBChannel *channel = (eDVBChannel*) it->first;
1167 channel_data *data = it->second;
1168 eDVBChannelID chid = channel->getChannelID();
1169 if ( chid.transport_stream_id.get() == msg.service.tsid &&
1170 chid.original_network_id.get() == msg.service.onid )
1172 data->m_mhw2_summary_pid = msg.pid;
1173 eDebug("[eEPGCache] got mhw2 summary pid %04x", msg.pid);
1180 case Message::timeChanged:
1184 eDebug("[eEPGCache] unhandled EPGCache Message!!");
1189 void eEPGCache::thread()
1199 static const char* EPGDAT_IN_FLASH = "/epg.dat";
1201 void eEPGCache::load()
1203 if (m_filename.empty())
1204 m_filename = "/hdd/epg.dat";
1205 const char* EPGDAT = m_filename.c_str();
1206 std::string filenamex = m_filename + ".loading";
1207 const char* EPGDATX = filenamex.c_str();
1208 FILE *f = fopen(EPGDAT, "rb");
1212 /* No EPG on harddisk, so try internal flash */
1213 eDebug("[eEPGCache] %s not found, try %s", EPGDAT, EPGDAT_IN_FLASH);
1214 EPGDAT = EPGDAT_IN_FLASH;
1215 f = fopen(EPGDAT, "rb");
1223 renameResult = rename(EPGDAT, EPGDATX);
1224 if (renameResult) eDebug("[eEPGCache] failed to rename %s", EPGDAT);
1229 unsigned int magic=0;
1230 unlink(EPGDAT_IN_FLASH);/* Don't keep it around when in flash */
1231 fread( &magic, sizeof(int), 1, f);
1232 if (magic != 0x98765432)
1234 eDebug("[eEPGCache] epg file has incorrect byte order.. dont read it");
1239 fread( text1, 13, 1, f);
1240 if ( !memcmp( text1, "ENIGMA_EPG_V7", 13) )
1242 singleLock s(cache_lock);
1243 fread( &size, sizeof(int), 1, f);
1244 eventDB.rehash(size); /* Reserve buckets in advance */
1249 fread( &key, sizeof(uniqueEPGKey), 1, f);
1250 fread( &size, sizeof(int), 1, f);
1251 EventCacheItem& item = eventDB[key]; /* Constructs new entry */
1257 fread( &type, sizeof(uint8_t), 1, f);
1258 fread( &len, sizeof(uint8_t), 1, f);
1259 event = new eventData(0, len, type);
1260 event->n_crc = (len-10) / sizeof(uint32_t);
1261 fread( event->rawEITdata, 10, 1, f);
1264 event->crc_list = new uint32_t[event->n_crc];
1265 fread( event->crc_list, sizeof(uint32_t), event->n_crc, f);
1267 eventData::CacheSize += sizeof(eventData) + event->n_crc * sizeof(uint32_t);
1268 item.byEvent[event->getEventID()] = event;
1269 item.byTime[event->getStartTime()] = event;
1274 eDebug("[eEPGCache] %d events read from %s", cnt, EPGDAT);
1275 #ifdef ENABLE_PRIVATE_EPG
1277 fread( text2, 11, 1, f);
1278 if ( !memcmp( text2, "PRIVATE_EPG", 11) )
1281 fread( &size, sizeof(int), 1, f);
1282 eventDB.rehash(size); /* Reserve buckets in advance */
1287 fread( &key, sizeof(uniqueEPGKey), 1, f);
1288 eventMap &evMap = eventDB[key].byEvent;
1289 fread( &size, sizeof(int), 1, f);
1294 fread( &content_id, sizeof(int), 1, f);
1295 fread( &size, sizeof(int), 1, f);
1298 time_t time1, time2;
1300 fread( &time1, sizeof(time_t), 1, f);
1301 fread( &time2, sizeof(time_t), 1, f);
1302 fread( &event_id, sizeof(uint16_t), 1, f);
1303 content_time_tables[key][content_id][time1]=std::pair<time_t, uint16_t>(time2, event_id);
1304 eventMap::iterator it =
1305 evMap.find(event_id);
1306 if (it != evMap.end())
1307 it->second->type = PRIVATE;
1312 #endif // ENABLE_PRIVATE_EPG
1315 eDebug("[eEPGCache] don't read old epg database");
1316 posix_fadvise(fileno(f), 0, 0, POSIX_FADV_DONTNEED);
1318 // We got this far, so the EPG file is okay.
1319 if (renameResult == 0)
1321 renameResult = rename(EPGDATX, EPGDAT);
1322 if (renameResult) eDebug("[eEPGCache] failed to rename epg.dat back");
1327 void eEPGCache::save()
1329 const char* EPGDAT = m_filename.c_str();
1330 if (eventData::isCacheCorrupt)
1332 // only save epg.dat if it's worth the trouble...
1333 if (eventData::CacheSize < 10240)
1336 /* create empty file */
1337 FILE *f = fopen(EPGDAT, "wb");
1340 eDebug("[eEPGCache] couldn't save epg data to '%s'(%m)", EPGDAT);
1341 EPGDAT = EPGDAT_IN_FLASH;
1342 f = fopen(EPGDAT, "wb");
1347 char *buf = realpath(EPGDAT, NULL);
1350 eDebug("[eEPGCache] realpath to '%s' failed in save (%m)", EPGDAT);
1355 eDebug("[eEPGCache] store epg to realpath '%s'", buf);
1359 if (statfs(buf, &s) < 0) {
1360 eDebug("[eEPGCache] statfs '%s' failed in save (%m)", buf);
1368 // check for enough free space on storage
1371 if ( tmp < (eventData::CacheSize*12)/10 ) // 20% overhead
1373 eDebug("[eEPGCache] not enough free space at '%s' %lld bytes available but %u needed", buf, tmp, (eventData::CacheSize*12)/10);
1379 unsigned int magic = 0x98765432;
1380 fwrite( &magic, sizeof(int), 1, f);
1381 const char *text = "UNFINISHED_V7";
1382 fwrite( text, 13, 1, f );
1383 int size = eventDB.size();
1384 fwrite( &size, sizeof(int), 1, f );
1385 for (eventCache::iterator service_it(eventDB.begin()); service_it != eventDB.end(); ++service_it)
1387 timeMap &timemap = service_it->second.byTime;
1388 fwrite( &service_it->first, sizeof(uniqueEPGKey), 1, f);
1389 size = timemap.size();
1390 fwrite( &size, sizeof(int), 1, f);
1391 for (timeMap::iterator time_it(timemap.begin()); time_it != timemap.end(); ++time_it)
1393 uint8_t len = time_it->second->n_crc * sizeof(uint32_t) + 10;
1394 fwrite( &time_it->second->type, sizeof(uint8_t), 1, f );
1395 fwrite( &len, sizeof(uint8_t), 1, f);
1396 fwrite( time_it->second->rawEITdata, 10, 1, f);
1397 fwrite( time_it->second->crc_list, sizeof(uint32_t), time_it->second->n_crc, f);
1401 eDebug("[eEPGCache] %d events written to %s", cnt, EPGDAT);
1403 #ifdef ENABLE_PRIVATE_EPG
1404 const char* text3 = "PRIVATE_EPG";
1405 fwrite( text3, 11, 1, f );
1406 size = content_time_tables.size();
1407 fwrite( &size, sizeof(int), 1, f);
1408 for (contentMaps::iterator a = content_time_tables.begin(); a != content_time_tables.end(); ++a)
1410 contentMap &content_time_table = a->second;
1411 fwrite( &a->first, sizeof(uniqueEPGKey), 1, f);
1412 int size = content_time_table.size();
1413 fwrite( &size, sizeof(int), 1, f);
1414 for (contentMap::iterator i = content_time_table.begin(); i != content_time_table.end(); ++i )
1416 int size = i->second.size();
1417 fwrite( &i->first, sizeof(int), 1, f);
1418 fwrite( &size, sizeof(int), 1, f);
1419 for ( contentTimeMap::iterator it(i->second.begin());
1420 it != i->second.end(); ++it )
1422 fwrite( &it->first, sizeof(time_t), 1, f);
1423 fwrite( &it->second.first, sizeof(time_t), 1, f);
1424 fwrite( &it->second.second, sizeof(uint16_t), 1, f);
1429 // write version string after binary data
1430 // has been written to disk.
1432 fseek(f, sizeof(int), SEEK_SET);
1433 fwrite("ENIGMA_EPG_V7", 13, 1, f);
1437 eEPGCache::channel_data::channel_data(eEPGCache *ml)
1439 ,abortTimer(eTimer::create(ml)), zapTimer(eTimer::create(ml)), state(-2)
1440 ,isRunning(0), haveData(0)
1441 #ifdef ENABLE_PRIVATE_EPG
1442 ,startPrivateTimer(eTimer::create(ml))
1444 #ifdef ENABLE_MHW_EPG
1445 ,m_MHWTimeoutTimer(eTimer::create(ml))
1448 #ifdef ENABLE_MHW_EPG
1449 CONNECT(m_MHWTimeoutTimer->timeout, eEPGCache::channel_data::MHWTimeout);
1451 CONNECT(zapTimer->timeout, eEPGCache::channel_data::startEPG);
1452 CONNECT(abortTimer->timeout, eEPGCache::channel_data::abortNonAvail);
1453 #ifdef ENABLE_PRIVATE_EPG
1454 CONNECT(startPrivateTimer->timeout, eEPGCache::channel_data::startPrivateReader);
1456 pthread_mutex_init(&channel_active, 0);
1459 void eEPGCache::channel_data::finishEPG()
1461 if (!isRunning) // epg ready
1463 eDebug("[eEPGCache] stop caching events(%ld)", ::time(0));
1464 zapTimer->start(UPDATE_INTERVAL, 1);
1465 eDebug("[eEPGCache] next update in %i min", UPDATE_INTERVAL / 60000);
1466 for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
1468 seenSections[i].clear();
1469 calcedSections[i].clear();
1471 #ifdef ENABLE_MHW_EPG
1474 #ifdef ENABLE_FREESAT
1477 singleLock l(cache_lock);
1478 cache->channelLastUpdated[channel->getChannelID()] = ::time(0);
1482 void eEPGCache::channel_data::startEPG()
1484 eDebug("[eEPGCache] start caching events(%ld)", ::time(0));
1487 for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
1489 seenSections[i].clear();
1490 calcedSections[i].clear();
1492 #ifdef ENABLE_MHW_EPG
1495 #ifdef ENABLE_FREESAT
1499 eDVBSectionFilterMask mask;
1500 memset(&mask, 0, sizeof(mask));
1502 #ifdef ENABLE_MHW_EPG
1503 if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::MHW)
1506 mask.data[0] = 0x91;
1507 mask.mask[0] = 0xFF;
1508 m_MHWReader->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData), m_MHWConn);
1509 m_MHWReader->start(mask);
1511 memcpy(&m_MHWFilterMask, &mask, sizeof(eDVBSectionFilterMask));
1513 mask.pid = m_mhw2_channel_pid;
1514 mask.data[0] = 0xC8;
1515 mask.mask[0] = 0xFF;
1517 mask.mask[1] = 0xFF;
1518 m_MHWReader2->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData2), m_MHWConn2);
1519 m_MHWReader2->start(mask);
1521 memcpy(&m_MHWFilterMask2, &mask, sizeof(eDVBSectionFilterMask));
1524 m_MHWTimeoutet=false;
1527 #ifdef ENABLE_FREESAT
1528 if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::FREESAT_SCHEDULE_OTHER)
1531 mask.flags = eDVBSectionFilterMask::rfCRC;
1532 mask.data[0] = 0x60;
1533 mask.mask[0] = 0xFE;
1534 m_FreeSatScheduleOtherReader->connectRead(slot(*this, &eEPGCache::channel_data::readFreeSatScheduleOtherData), m_FreeSatScheduleOtherConn);
1535 m_FreeSatScheduleOtherReader->start(mask);
1538 * faster pid, available on ITV HD transponder.
1539 * We rely on the fact that we have either of the two,
1540 * never both. (both readers share the same data callback
1544 m_FreeSatScheduleOtherReader2->connectRead(slot(*this, &eEPGCache::channel_data::readFreeSatScheduleOtherData), m_FreeSatScheduleOtherConn2);
1545 m_FreeSatScheduleOtherReader2->start(mask);
1546 isRunning |= FREESAT_SCHEDULE_OTHER;
1550 mask.flags = eDVBSectionFilterMask::rfCRC;
1552 if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::NOWNEXT)
1554 mask.data[0] = 0x4E;
1555 mask.mask[0] = 0xFE;
1556 m_NowNextReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::NOWNEXT), m_NowNextConn);
1557 m_NowNextReader->start(mask);
1558 isRunning |= NOWNEXT;
1561 if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::SCHEDULE)
1563 mask.data[0] = 0x50;
1564 mask.mask[0] = 0xF0;
1565 m_ScheduleReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::SCHEDULE), m_ScheduleConn);
1566 m_ScheduleReader->start(mask);
1567 isRunning |= SCHEDULE;
1570 if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::SCHEDULE_OTHER)
1572 mask.data[0] = 0x60;
1573 mask.mask[0] = 0xF0;
1574 m_ScheduleOtherReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::SCHEDULE_OTHER), m_ScheduleOtherConn);
1575 m_ScheduleOtherReader->start(mask);
1576 isRunning |= SCHEDULE_OTHER;
1579 #ifdef ENABLE_VIRGIN
1580 if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::VIRGIN_NOWNEXT)
1583 mask.data[0] = 0x4E;
1584 mask.mask[0] = 0xFE;
1585 m_VirginNowNextReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::VIRGIN_NOWNEXT), m_VirginNowNextConn);
1586 m_VirginNowNextReader->start(mask);
1587 isRunning |= VIRGIN_NOWNEXT;
1590 if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::VIRGIN_SCHEDULE)
1593 mask.data[0] = 0x50;
1594 mask.mask[0] = 0xFE;
1595 m_VirginScheduleReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::VIRGIN_SCHEDULE), m_VirginScheduleConn);
1596 m_VirginScheduleReader->start(mask);
1597 isRunning |= VIRGIN_SCHEDULE;
1600 #ifdef ENABLE_NETMED
1601 if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::NETMED_SCHEDULE)
1604 mask.data[0] = 0x50;
1605 mask.mask[0] = 0xF0;
1606 m_NetmedScheduleReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::NETMED_SCHEDULE), m_NetmedScheduleConn);
1607 m_NetmedScheduleReader->start(mask);
1608 isRunning |= NETMED_SCHEDULE;
1611 if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::NETMED_SCHEDULE_OTHER)
1614 mask.data[0] = 0x60;
1615 mask.mask[0] = 0xF0;
1616 m_NetmedScheduleOtherReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::NETMED_SCHEDULE_OTHER), m_NetmedScheduleOtherConn);
1617 m_NetmedScheduleOtherReader->start(mask);
1618 isRunning |= NETMED_SCHEDULE_OTHER;
1621 if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::VIASAT)
1625 mask.data[0] = 0x40;
1626 mask.mask[0] = 0x40;
1627 m_ViasatReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::VIASAT), m_ViasatConn);
1628 m_ViasatReader->start(mask);
1629 isRunning |= VIASAT;
1632 abortTimer->start(7000,true);
1635 void eEPGCache::channel_data::abortNonAvail()
1639 if ( !(haveData&NOWNEXT) && (isRunning&NOWNEXT) )
1641 eDebug("[eEPGCache] abort non avail nownext reading");
1642 isRunning &= ~NOWNEXT;
1643 m_NowNextReader->stop();
1646 if ( !(haveData&SCHEDULE) && (isRunning&SCHEDULE) )
1648 eDebug("[eEPGCache] abort non avail schedule reading");
1649 isRunning &= ~SCHEDULE;
1650 m_ScheduleReader->stop();
1653 if ( !(haveData&SCHEDULE_OTHER) && (isRunning&SCHEDULE_OTHER) )
1655 eDebug("[eEPGCache] abort non avail schedule other reading");
1656 isRunning &= ~SCHEDULE_OTHER;
1657 m_ScheduleOtherReader->stop();
1658 m_ScheduleOtherConn=0;
1660 #ifdef ENABLE_VIRGIN
1661 if ( !(haveData&VIRGIN_NOWNEXT) && (isRunning&VIRGIN_NOWNEXT) )
1663 eDebug("[eEPGCache] abort non avail virgin nownext reading");
1664 isRunning &= ~VIRGIN_NOWNEXT;
1665 m_VirginNowNextReader->stop();
1666 m_VirginNowNextConn=0;
1668 if ( !(haveData&VIRGIN_SCHEDULE) && (isRunning&VIRGIN_SCHEDULE) )
1670 eDebug("[eEPGCache] abort non avail virgin schedule reading");
1671 isRunning &= ~VIRGIN_SCHEDULE;
1672 m_VirginScheduleReader->stop();
1673 m_VirginScheduleConn=0;
1676 #ifdef ENABLE_NETMED
1677 if ( !(haveData&NETMED_SCHEDULE) && (isRunning&NETMED_SCHEDULE) )
1679 eDebug("[eEPGCache] abort non avail netmed schedule reading");
1680 isRunning &= ~NETMED_SCHEDULE;
1681 m_NetmedScheduleReader->stop();
1682 m_NetmedScheduleConn=0;
1684 if ( !(haveData&NETMED_SCHEDULE_OTHER) && (isRunning&NETMED_SCHEDULE_OTHER) )
1686 eDebug("[eEPGCache] abort non avail netmed schedule other reading");
1687 isRunning &= ~NETMED_SCHEDULE_OTHER;
1688 m_NetmedScheduleOtherReader->stop();
1689 m_NetmedScheduleOtherConn=0;
1692 #ifdef ENABLE_FREESAT
1693 if ( !(haveData&FREESAT_SCHEDULE_OTHER) && (isRunning&FREESAT_SCHEDULE_OTHER) )
1695 eDebug("[eEPGCache] abort non avail FreeSat schedule_other reading");
1696 isRunning &= ~FREESAT_SCHEDULE_OTHER;
1697 m_FreeSatScheduleOtherReader->stop();
1698 m_FreeSatScheduleOtherReader2->stop();
1699 m_FreeSatScheduleOtherConn=0;
1700 m_FreeSatScheduleOtherConn2=0;
1704 if ( !(haveData&VIASAT) && (isRunning&VIASAT) )
1706 eDebug("[eEPGCache] abort non avail viasat reading");
1707 isRunning &= ~VIASAT;
1708 m_ViasatReader->stop();
1711 #ifdef ENABLE_MHW_EPG
1712 if ( !(haveData&MHW) && (isRunning&MHW) )
1714 eDebug("[eEPGCache] abort non avail mhw reading");
1716 m_MHWReader->stop();
1718 m_MHWReader2->stop();
1722 if ( isRunning & VIASAT )
1723 abortTimer->start(300000, true);
1724 else if ( isRunning )
1725 abortTimer->start(90000, true);
1729 for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
1731 seenSections[i].clear();
1732 calcedSections[i].clear();
1734 #ifdef ENABLE_MHW_EPG
1737 #ifdef ENABLE_FREESAT
1745 void eEPGCache::channel_data::startChannel()
1747 pthread_mutex_lock(&channel_active);
1748 updateMap::iterator It = cache->channelLastUpdated.find( channel->getChannelID() );
1750 int update = ( It != cache->channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (::time(0)-It->second) * 1000 ) ) : ZAP_DELAY );
1752 if (update < ZAP_DELAY)
1755 zapTimer->start(update, 1);
1756 if (update >= 60000)
1757 eDebug("[eEPGCache] next update in %i min", update/60000);
1758 else if (update >= 1000)
1759 eDebug("[eEPGCache] next update in %i sec", update/1000);
1762 void eEPGCache::channel_data::abortEPG()
1764 for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i)
1766 seenSections[i].clear();
1767 calcedSections[i].clear();
1769 #ifdef ENABLE_MHW_EPG
1772 #ifdef ENABLE_FREESAT
1779 eDebug("[eEPGCache] abort caching events !!");
1780 if (isRunning & SCHEDULE)
1782 isRunning &= ~SCHEDULE;
1783 m_ScheduleReader->stop();
1786 if (isRunning & NOWNEXT)
1788 isRunning &= ~NOWNEXT;
1789 m_NowNextReader->stop();
1792 if (isRunning & SCHEDULE_OTHER)
1794 isRunning &= ~SCHEDULE_OTHER;
1795 m_ScheduleOtherReader->stop();
1796 m_ScheduleOtherConn=0;
1798 #ifdef ENABLE_VIRGIN
1799 if (isRunning & VIRGIN_NOWNEXT)
1801 isRunning &= ~VIRGIN_NOWNEXT;
1802 m_VirginNowNextReader->stop();
1803 m_VirginNowNextConn=0;
1805 if (isRunning & VIRGIN_SCHEDULE)
1807 isRunning &= ~VIRGIN_SCHEDULE;
1808 m_VirginScheduleReader->stop();
1809 m_VirginScheduleConn=0;
1812 #ifdef ENABLE_NETMED
1813 if (isRunning & NETMED_SCHEDULE)
1815 isRunning &= ~NETMED_SCHEDULE;
1816 m_NetmedScheduleReader->stop();
1817 m_NetmedScheduleConn=0;
1819 if (isRunning & NETMED_SCHEDULE_OTHER)
1821 isRunning &= ~NETMED_SCHEDULE_OTHER;
1822 m_NetmedScheduleOtherReader->stop();
1823 m_NetmedScheduleOtherConn=0;
1826 #ifdef ENABLE_FREESAT
1827 if (isRunning & FREESAT_SCHEDULE_OTHER)
1829 isRunning &= ~FREESAT_SCHEDULE_OTHER;
1830 m_FreeSatScheduleOtherReader->stop();
1831 m_FreeSatScheduleOtherReader2->stop();
1832 m_FreeSatScheduleOtherConn=0;
1833 m_FreeSatScheduleOtherConn2=0;
1836 if (isRunning & VIASAT)
1838 isRunning &= ~VIASAT;
1839 m_ViasatReader->stop();
1842 #ifdef ENABLE_MHW_EPG
1843 if (isRunning & MHW)
1846 m_MHWReader->stop();
1848 m_MHWReader2->stop();
1853 #ifdef ENABLE_PRIVATE_EPG
1854 if (m_PrivateReader)
1855 m_PrivateReader->stop();
1859 pthread_mutex_unlock(&channel_active);
1862 void eEPGCache::channel_data::readData( const uint8_t *data, int source)
1865 iDVBSectionReader *reader = NULL;
1869 reader = m_NowNextReader;
1873 reader = m_ScheduleReader;
1876 case SCHEDULE_OTHER:
1877 reader = m_ScheduleOtherReader;
1881 reader = m_ViasatReader;
1884 #ifdef ENABLE_NETMED
1885 case NETMED_SCHEDULE:
1886 reader = m_NetmedScheduleReader;
1889 case NETMED_SCHEDULE_OTHER:
1890 reader = m_NetmedScheduleOtherReader;
1894 #ifdef ENABLE_VIRGIN
1895 case VIRGIN_NOWNEXT:
1896 reader = m_VirginNowNextReader;
1899 case VIRGIN_SCHEDULE:
1900 reader = m_VirginScheduleReader;
1905 eDebug("[eEPGCache] unknown source");
1908 tidMap &seenSections = this->seenSections[map];
1909 tidMap &calcedSections = this->calcedSections[map];
1910 if ( (state == 1 && calcedSections == seenSections) || state > 1 )
1912 eDebugNoNewLine("[eEPGCache] ");
1917 eDebugNoNewLine("nownext");
1921 eDebugNoNewLine("schedule");
1923 case SCHEDULE_OTHER:
1924 m_ScheduleOtherConn=0;
1925 eDebugNoNewLine("schedule other");
1929 eDebugNoNewLine("viasat");
1931 #ifdef ENABLE_NETMED
1932 case NETMED_SCHEDULE:
1933 m_NetmedScheduleConn=0;
1934 eDebugNoNewLine("netmed schedule");
1936 case NETMED_SCHEDULE_OTHER:
1937 m_NetmedScheduleOtherConn=0;
1938 eDebugNoNewLine("netmed schedule other");
1941 #ifdef ENABLE_VIRGIN
1942 case VIRGIN_NOWNEXT:
1943 m_VirginNowNextConn=0;
1944 eDebugNoNewLine("virgin nownext");
1946 case VIRGIN_SCHEDULE:
1947 m_VirginScheduleConn=0;
1948 eDebugNoNewLine("virgin schedule");
1951 default: eDebugNoNewLine("unknown");break;
1953 eDebugNoNewLine(" finished(%ld)\n", ::time(0));
1956 isRunning &= ~source;
1962 eit_t *eit = (eit_t*) data;
1963 uint32_t sectionNo = data[0] << 24;
1964 sectionNo |= data[3] << 16;
1965 sectionNo |= data[4] << 8;
1966 sectionNo |= eit->section_number;
1968 tidMap::iterator it =
1969 seenSections.find(sectionNo);
1971 if ( it == seenSections.end() )
1973 seenSections.insert(sectionNo);
1974 calcedSections.insert(sectionNo);
1975 uint32_t tmpval = sectionNo & 0xFFFFFF00;
1976 uint8_t incr = source == NOWNEXT ? 1 : 8;
1977 for ( int i = 0; i <= eit->last_section_number; i+=incr )
1979 if ( i == eit->section_number )
1981 for (int x=i; x <= eit->segment_last_section_number; ++x)
1983 calcedSections.insert(tmpval|(x&0xFF));
1988 calcedSections.insert(tmpval|(i&0xFF));
1991 cache->sectionRead(data, source, this);
1998 freesatEITSubtableStatus::freesatEITSubtableStatus(u_char version, uint8_t maxSection) : version(version)
2000 initMap(maxSection);
2003 void freesatEITSubtableStatus::initMap(uint8_t maxSection)
2005 int i, maxSectionIdx = maxSection / 8;
2006 for (i = 0; i < 32; i++)
2008 sectionMap[i] = (i <= maxSectionIdx ? 0x0100 : 0x0000 );
2012 bool freesatEITSubtableStatus::isSectionPresent(uint8_t sectionNo)
2014 uint8_t sectionIdx = sectionNo / 8;
2015 uint8_t bitOffset = sectionNo % 8;
2017 return ((sectionMap[sectionIdx] & (1 << bitOffset)) != 0);
2020 bool freesatEITSubtableStatus::isCompleted()
2027 calc = sectionMap[i] >> 8;
2028 if (! calc) return true; // Last segment passed
2029 if (calc ^ ( sectionMap[i] & 0xFF ) ) // Segment not fully found
2033 return true; // All segments ok
2036 void freesatEITSubtableStatus::seen(uint8_t sectionNo, uint8_t maxSegmentSection)
2038 uint8_t sectionIdx = sectionNo / 8;
2039 uint8_t bitOffset = sectionNo % 8;
2040 uint8_t maxBitOffset = maxSegmentSection % 8;
2042 sectionMap[sectionIdx] &= 0x00FF; // Clear calc map
2043 sectionMap[sectionIdx] |= ((0x01FF << maxBitOffset) & 0xFF00); // Set calc map
2044 sectionMap[sectionIdx] |= (1 << bitOffset); // Set seen map
2047 bool freesatEITSubtableStatus::isVersionChanged(u_char testVersion)
2049 return version != testVersion;
2052 void freesatEITSubtableStatus::updateVersion(u_char newVersion, uint8_t maxSection)
2054 version = newVersion;
2055 initMap(maxSection);
2058 void eEPGCache::channel_data::cleanupFreeSat()
2060 m_FreeSatSubTableStatus.clear();
2061 m_FreesatTablesToComplete = 0;
2064 void eEPGCache::channel_data::readFreeSatScheduleOtherData( const uint8_t *data)
2066 eit_t *eit = (eit_t*) data;
2067 uint32_t subtableNo = data[0] << 24; // Table ID
2068 subtableNo |= data[3] << 16; // Service ID Hi
2069 subtableNo |= data[4] << 8; // Service ID Lo
2071 // Check for sub-table version in map
2072 std::map<uint32_t, freesatEITSubtableStatus> &freeSatSubTableStatus = this->m_FreeSatSubTableStatus;
2073 std::map<uint32_t, freesatEITSubtableStatus>::iterator itmap = freeSatSubTableStatus.find(subtableNo);
2075 freesatEITSubtableStatus *fsstatus;
2076 if ( itmap == freeSatSubTableStatus.end() )
2078 // New sub table. Store version.
2079 //eDebug("[eEPGCache] New subtable (%x) version (%d) now/next (%d) tsid (%x/%x) onid (%x/%x)", subtableNo, eit->version_number, eit->current_next_indicator, eit->transport_stream_id_hi, eit->transport_stream_id_lo, eit->original_network_id_hi, eit->original_network_id_lo);
2080 fsstatus = new freesatEITSubtableStatus(eit->version_number, eit->last_section_number);
2081 m_FreesatTablesToComplete++;
2082 freeSatSubTableStatus.insert(std::pair<uint32_t,freesatEITSubtableStatus>(subtableNo, *fsstatus));
2086 fsstatus = &itmap->second;
2087 // Existing subtable. Check version. Should check current / next as well? Seems to always be current for Freesat
2088 if ( fsstatus->isVersionChanged(eit->version_number) )
2090 eDebug("[eEPGCache] FS subtable (%x) version changed (%d) now/next (%d)", subtableNo, eit->version_number, eit->current_next_indicator);
2091 m_FreesatTablesToComplete++;
2092 fsstatus->updateVersion(eit->version_number, eit->last_section_number);
2096 if ( fsstatus->isSectionPresent(eit->section_number) )
2098 // eDebug("[eEPGCache] DUP FS sub/sec/ver (%x/%d/%d)", subtableNo, eit->section_number, eit->version_number);
2104 // eDebug("[eEPGCache] New FS sub/sec/ls/lss/ver (%x/%d/%d/%d/%d)", subtableNo, eit->section_number, eit->last_section_number, eit->segment_last_section_number, eit->version_number);
2105 fsstatus->seen(eit->section_number, eit->segment_last_section_number);
2106 if (fsstatus->isCompleted())
2108 m_FreesatTablesToComplete--;
2110 cache->sectionRead(data, FREESAT_SCHEDULE_OTHER, this);
2114 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result, int direction)
2115 // if t == -1 we search the current event...
2117 uniqueEPGKey key(handleGroup(service));
2119 // check if EPG for this service is ready...
2120 eventCache::iterator It = eventDB.find( key );
2121 if ( It != eventDB.end() && !It->second.byEvent.empty() ) // entrys cached ?
2125 timeMap::iterator i = direction <= 0 ? It->second.byTime.lower_bound(t) : // find > or equal
2126 It->second.byTime.upper_bound(t); // just >
2127 if ( i != It->second.byTime.end() )
2129 if ( direction < 0 || (direction == 0 && i->first > t) )
2131 timeMap::iterator x = i;
2133 if ( x != It->second.byTime.end() )
2135 time_t start_time = x->first;
2140 if (t > (start_time+x->second->getDuration()))
2155 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, Event *& result, int direction)
2157 singleLock s(cache_lock);
2158 const eventData *data=0;
2159 RESULT ret = lookupEventTime(service, t, data, direction);
2161 result = new Event((uint8_t*)data->get());
2165 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, ePtr<eServiceEvent> &result, int direction)
2167 singleLock s(cache_lock);
2168 const eventData *data=0;
2169 RESULT ret = lookupEventTime(service, t, data, direction);
2173 Event ev((uint8_t*)data->get());
2174 result = new eServiceEvent();
2175 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
2176 ret = result->parseFrom(&ev, (ref.getTransportStreamID().get()<<16)|ref.getOriginalNetworkID().get());
2181 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eventData *&result )
2183 uniqueEPGKey key(handleGroup(service));
2185 eventCache::iterator It = eventDB.find(key);
2186 if (It != eventDB.end())
2188 eventMap::iterator i = It->second.byEvent.find(event_id);
2189 if ( i != It->second.byEvent.end() )
2197 eDebug("[eEPGCache] event %04x not found in epgcache", event_id);
2203 RESULT eEPGCache::saveEventToFile(const char* filename, const eServiceReference &service, int eit_event_id, time_t begTime, time_t endTime)
2206 singleLock s(cache_lock);
2207 const eventData *data = NULL;
2208 if ( eit_event_id != -1 )
2210 eDebug("[eEPGCache] %s epg event id %x", __func__, eit_event_id);
2211 ret = lookupEventId(service, eit_event_id, data);
2213 if ( (ret != 0) && (begTime != -1) )
2215 time_t queryTime = begTime;
2217 queryTime += (endTime - begTime) / 2;
2218 ret = lookupEventTime(service, queryTime, data);
2222 int fd = open(filename, O_CREAT|O_WRONLY, 0666);
2225 eDebug("[eEPGCache] Failed to create file: %s", filename);
2228 const eit_event_struct *event = data->get();
2229 int evLen = event->getDescriptorsLoopLength() + 12/*EIT_LOOP_SIZE*/;
2230 int wr = ::write( fd, event, evLen );
2234 ::unlink(filename); /* Remove faulty file */
2235 eDebug("[eEPGCache] eit write error on %s: %m", filename);
2236 ret = (wr < 0) ? wr : -1;
2242 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, Event *& result)
2244 singleLock s(cache_lock);
2245 const eventData *data=0;
2246 RESULT ret = lookupEventId(service, event_id, data);
2248 result = new Event((uint8_t*)data->get());
2252 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, ePtr<eServiceEvent> &result)
2254 singleLock s(cache_lock);
2255 const eventData *data=0;
2256 RESULT ret = lookupEventId(service, event_id, data);
2260 Event ev((uint8_t*)data->get());
2261 result = new eServiceEvent();
2262 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
2263 ret = result->parseFrom(&ev, (ref.getTransportStreamID().get()<<16)|ref.getOriginalNetworkID().get());
2268 RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, int minutes)
2270 singleLock s(cache_lock);
2271 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)handleGroup(service);
2274 eventCache::iterator It = eventDB.find(ref);
2275 if ( It != eventDB.end() && !It->second.byTime.empty() )
2277 m_timemap_cursor = It->second.byTime.lower_bound(begin);
2278 if ( m_timemap_cursor != It->second.byTime.end() )
2280 if ( m_timemap_cursor->first != begin )
2282 timeMap::iterator x = m_timemap_cursor;
2284 if ( x != It->second.byTime.end() )
2286 time_t start_time = x->first;
2287 if ( begin > start_time && begin < (start_time+x->second->getDuration()))
2288 m_timemap_cursor = x;
2294 m_timemap_end = It->second.byTime.lower_bound(begin+minutes*60);
2296 m_timemap_end = It->second.byTime.end();
2298 currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get();
2299 return m_timemap_cursor == m_timemap_end ? -1 : 0;
2304 RESULT eEPGCache::getNextTimeEntry(Event *&result)
2306 if ( m_timemap_cursor != m_timemap_end )
2308 result = new Event((uint8_t*)m_timemap_cursor++->second->get());
2314 RESULT eEPGCache::getNextTimeEntry(ePtr<eServiceEvent> &result)
2316 if ( m_timemap_cursor != m_timemap_end )
2318 Event ev((uint8_t*)m_timemap_cursor++->second->get());
2319 result = new eServiceEvent();
2320 return result->parseFrom(&ev, currentQueryTsidOnid);
2325 void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject service_reference, eServiceEvent *ptr, ePyObject service_name, ePyObject nowTime, eventData *evData )
2327 //eDebug("[eEPGCache] fillTuple arg=%s argcnt=%d, ptr=%d evData=%d", argstring, argcount, ptr ? 1 : 0, evData ? 1 : 0);
2331 while(spos < argcount)
2333 bool inc_refcount=false;
2334 switch((c=argstring[spos++]))
2336 case '0': // PyLong 0
2337 tmp = PyLong_FromLong(0);
2339 case 'I': // Event Id
2340 tmp = evData ? PyLong_FromLong(evData->getEventID()) : (ptr ? PyLong_FromLong(ptr->getEventId()) : ePyObject());
2342 case 'B': // Event Begin Time
2343 tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : (evData ? PyLong_FromLong(evData->getStartTime()) : ePyObject());
2345 case 'D': // Event Duration
2346 tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : (evData ? PyLong_FromLong(evData->getDuration()) : ePyObject());
2348 case 'T': // Event Title
2349 tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : ePyObject();
2351 case 'S': // Event Short Description
2352 tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : ePyObject();
2354 case 'E': // Event Extended Description
2355 tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : ePyObject();
2357 case 'P': // Event Parental Rating
2358 tmp = ptr ? ePyObject(ptr->getParentalData()) : ePyObject();
2360 case 'W': // Event Content Description
2361 tmp = ptr ? ePyObject(ptr->getGenreData()) : ePyObject();
2363 case 'C': // Current Time
2365 inc_refcount = true;
2367 case 'R': // service reference string
2368 tmp = service_reference;
2369 inc_refcount = true;
2371 case 'n': // short service name
2372 case 'N': // service name
2374 inc_refcount = true;
2379 default: // ignore unknown
2381 eDebug("[eEPGCache] fillTuple unknown '%c'... insert 'None' in result", c);
2386 inc_refcount = true;
2390 PyTuple_SET_ITEM(tuple, tpos++, tmp);
2394 int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring, int argcount, ePyObject service, ePyObject nowTime, ePyObject service_name, ePyObject convertFunc, ePyObject convertFuncArgs)
2398 fillTuple(convertFuncArgs, argstring, argcount, service, ptr, service_name, nowTime, 0);
2399 ePyObject result = PyObject_CallObject(convertFunc, convertFuncArgs);
2403 Py_DECREF(service_name);
2406 Py_DECREF(convertFuncArgs);
2407 Py_DECREF(dest_list);
2408 PyErr_SetString(PyExc_StandardError,
2409 "error in convertFunc execute");
2410 eDebug("[eEPGCache] handleEvent: error in convertFunc execute");
2413 PyList_Append(dest_list, result);
2418 ePyObject tuple = PyTuple_New(argcount);
2419 fillTuple(tuple, argstring, argcount, service, ptr, service_name, nowTime, 0);
2420 PyList_Append(dest_list, tuple);
2426 // here we get a python list
2427 // the first entry in the list is a python string to specify the format of the returned tuples (in a list)
2430 // B = Event Begin Time
2431 // D = Event Duration
2433 // S = Event Short Description
2434 // E = Event Extended Description
2435 // P = Event Parental Rating
2436 // W = Event Content Description ('W'hat)
2438 // R = Service Reference
2440 // n = Short Service Name
2441 // X = Return a minimum of one tuple per service in the result list... even when no event was found.
2442 // The returned tuple is filled with all available infos... non avail is filled as None
2443 // The position and existence of 'X' in the format string has no influence on the result tuple... its completely ignored..
2444 // then for each service follows a tuple
2445 // first tuple entry is the servicereference (as string... use the ref.toString() function)
2446 // the second is the type of query
2448 // -1 = event before given start_time
2449 // 0 = event intersects given start_time
2450 // +1 = event after given start_time
2452 // when type is eventid it is the event_id
2453 // when type is time then it is the start_time ( -1 for now_time )
2454 // the fourth is the end_time .. ( optional .. for query all events in time range)
2456 PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc)
2458 ePyObject convertFuncArgs;
2460 const char *argstring=NULL;
2461 if (!PyList_Check(list))
2463 PyErr_SetString(PyExc_StandardError,
2465 eDebug("[eEPGCache] no list");
2469 int listSize=PyList_Size(list);
2472 PyErr_SetString(PyExc_StandardError,
2474 eDebug("[eEPGCache] no params given");
2479 ePyObject argv=PyList_GET_ITEM(list, 0); // borrowed reference!
2480 if (PyString_Check(argv))
2482 argstring = PyString_AS_STRING(argv);
2486 argstring = "I"; // just event id as default
2487 argcount = strlen(argstring);
2488 // eDebug("[eEPGCache] have %d args('%s')", argcount, argstring);
2491 bool forceReturnOne = strchr(argstring, 'X') ? true : false;
2497 if (!PyCallable_Check(convertFunc))
2499 PyErr_SetString(PyExc_StandardError,
2500 "convertFunc must be callable");
2501 eDebug("[eEPGCache] convertFunc is not callable");
2504 convertFuncArgs = PyTuple_New(argcount);
2507 ePyObject nowTime = strchr(argstring, 'C') ?
2508 PyLong_FromLong(::time(0)) :
2511 int must_get_service_name = strchr(argstring, 'N') ? 1 : strchr(argstring, 'n') ? 2 : 0;
2514 ePyObject dest_list=PyList_New(0);
2515 while(listSize > listIt)
2517 ePyObject item=PyList_GET_ITEM(list, listIt++); // borrowed reference!
2518 if (PyTuple_Check(item))
2520 bool service_changed=false;
2525 int tupleSize=PyTuple_Size(item);
2528 while(tupleSize > tupleIt) // parse query args
2530 ePyObject entry=PyTuple_GET_ITEM(item, tupleIt); // borrowed reference!
2535 if (!PyString_Check(entry))
2537 eDebug("[eEPGCache] tuple entry 0 is no a string");
2544 type=PyInt_AsLong(entry);
2545 if (type < -1 || type > 2)
2547 eDebug("[eEPGCache] unknown type %d", type);
2552 event_id=stime=PyInt_AsLong(entry);
2555 minutes=PyInt_AsLong(entry);
2558 eDebug("[eEPGCache] unneeded extra argument");
2563 if (minutes && stime == -1)
2566 eServiceReference ref(handleGroup(eServiceReference(PyString_AS_STRING(service))));
2567 // redirect subservice querys to parent service
2568 eServiceReferenceDVB &dvb_ref = (eServiceReferenceDVB&)ref;
2569 if (dvb_ref.getParentTransportStreamID().get()) // linkage subservice
2571 eServiceCenterPtr service_center;
2572 if (!eServiceCenter::getPrivInstance(service_center))
2574 dvb_ref.setTransportStreamID( dvb_ref.getParentTransportStreamID() );
2575 dvb_ref.setServiceID( dvb_ref.getParentServiceID() );
2576 dvb_ref.setParentTransportStreamID(eTransportStreamID(0));
2577 dvb_ref.setParentServiceID(eServiceID(0));
2579 service = PyString_FromString(dvb_ref.toString().c_str());
2580 service_changed = true;
2584 ePyObject service_name;
2585 if (must_get_service_name)
2587 ePtr<iStaticServiceInformation> sptr;
2588 eServiceCenterPtr service_center;
2589 eServiceCenter::getPrivInstance(service_center);
2592 service_center->info(ref, sptr);
2596 sptr->getName(ref, name);
2598 if (must_get_service_name == 1)
2601 // filter short name brakets
2602 while((pos = name.find("\xc2\x86")) != std::string::npos)
2604 while((pos = name.find("\xc2\x87")) != std::string::npos)
2608 name = buildShortName(name);
2611 service_name = PyString_FromString(name.c_str());
2615 service_name = PyString_FromString("<n/a>");
2619 singleLock s(cache_lock);
2620 if (!startTimeQuery(ref, stime, minutes))
2622 while ( m_timemap_cursor != m_timemap_end )
2624 Event ev((uint8_t*)m_timemap_cursor++->second->get());
2626 evt.parseFrom(&ev, currentQueryTsidOnid);
2627 if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
2631 else if (forceReturnOne && handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
2637 const eventData *ev_data=0;
2640 singleLock s(cache_lock);
2642 lookupEventId(ref, event_id, ev_data);
2644 lookupEventTime(ref, stime, ev_data, type);
2647 const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref;
2648 Event ev((uint8_t*)ev_data->get());
2649 evt.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
2654 if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
2657 else if (forceReturnOne && handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs))
2660 if (service_changed)
2663 Py_DECREF(service_name);
2668 if (convertFuncArgs)
2669 Py_DECREF(convertFuncArgs);
2675 static void fill_eit_start(eit_event_struct *evt, time_t t)
2677 tm *time = gmtime(&t);
2680 int month = time->tm_mon + 1;
2681 if (month == 1 || month == 2)
2683 int mjd = 14956 + time->tm_mday + (int)((time->tm_year - l) * 365.25) + (int)((month + 1 + l*12) * 30.6001);
2684 evt->start_time_1 = mjd >> 8;
2685 evt->start_time_2 = mjd & 0xFF;
2687 evt->start_time_3 = toBCD(time->tm_hour);
2688 evt->start_time_4 = toBCD(time->tm_min);
2689 evt->start_time_5 = toBCD(time->tm_sec);
2693 static void fill_eit_duration(eit_event_struct *evt, int time)
2695 //time is given in second
2696 //convert to hour, minutes, seconds
2697 evt->duration_1 = toBCD(time / 3600);
2698 evt->duration_2 = toBCD((time % 3600) / 60);
2699 evt->duration_3 = toBCD((time % 3600) % 60);
2702 // convert from set of strings to DVB format (EIT)
2703 void eEPGCache::submitEventData(const std::vector<eServiceReferenceDVB>& serviceRefs, long start,
2704 long duration, const char* title, const char* short_summary,
2705 const char* long_description, char event_type)
2707 std::vector<int> sids;
2708 std::vector<eDVBChannelID> chids;
2709 for (std::vector<eServiceReferenceDVB>::const_iterator serviceRef = serviceRefs.begin();
2710 serviceRef != serviceRefs.end();
2714 serviceRef->getChannelID(chid);
2715 chids.push_back(chid);
2716 sids.push_back(serviceRef->getServiceID().get());
2718 submitEventData(sids, chids, start, duration, title, short_summary, long_description, event_type, EPG_IMPORT);
2721 void eEPGCache::submitEventData(const std::vector<int>& sids, const std::vector<eDVBChannelID>& chids, long start,
2722 long duration, const char* title, const char* short_summary,
2723 const char* long_description, char event_type, int source)
2727 if (sids.size() != chids.size())
2729 static const int EIT_LENGTH = 4108;
2730 static const uint8_t codePage = 0x15; // UTF-8 encoding
2731 uint8_t data[EIT_LENGTH];
2733 eit_t *packet = (eit_t *) data;
2734 packet->table_id = 0x50;
2735 packet->section_syntax_indicator = 1;
2737 packet->version_number = 0; // eEPGCache::sectionRead() will dig this for the moment
2738 packet->current_next_indicator = 0;
2739 packet->section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
2740 packet->last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
2742 packet->segment_last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
2743 packet->segment_last_table_id = 0x50;
2745 eit_event_t *evt_struct = (eit_event_t*) (data + EIT_SIZE);
2747 uint16_t eventId = start & 0xFFFF;
2748 evt_struct->setEventId(eventId);
2750 //6 bytes start time, 3 bytes duration
2751 fill_eit_start(evt_struct, start);
2752 fill_eit_duration(evt_struct, duration);
2754 evt_struct->running_status = 0;
2755 evt_struct->free_CA_mode = 0;
2757 //no support for different code pages, only DVB's latin1 character set
2758 //TODO: convert text to correct character set (data is probably passed in as UTF-8)
2759 uint8_t *x = (uint8_t *) evt_struct;
2761 int nameLength = strnlen(title, 246);
2762 int descLength = short_summary ? strnlen(short_summary, 246 - nameLength) : 0;
2764 eit_short_event_descriptor_struct *short_evt = (eit_short_event_descriptor_struct*) x;
2765 short_evt->descriptor_tag = SHORT_EVENT_DESCRIPTOR;
2766 short_evt->descriptor_length = EIT_SHORT_EVENT_DESCRIPTOR_SIZE + nameLength + descLength + 1 - 2; //+1 for length of short description, -2 for tag and length
2767 if (nameLength) ++short_evt->descriptor_length; // +1 for codepage byte
2768 if (descLength) ++short_evt->descriptor_length;
2769 short_evt->language_code_1 = 'e';
2770 short_evt->language_code_2 = 'n';
2771 short_evt->language_code_3 = 'g';
2772 short_evt->event_name_length = nameLength ? nameLength + 1 : 0;
2773 x = (uint8_t *) short_evt;
2774 x += EIT_SHORT_EVENT_DESCRIPTOR_SIZE;
2777 memcpy(x, title, nameLength);
2781 *x = descLength + 1;
2785 memcpy(x, short_summary, descLength);
2795 if (event_type != 0)
2805 int currentLoopLength = x - (uint8_t*)short_evt;
2806 static const int overheadPerDescriptor = 9; //increase if codepages are added!!!
2807 static const int MAX_LEN = 256 - overheadPerDescriptor;
2809 int textLength = long_description ? strnlen(long_description, EIT_LENGTH) : 0;//EIT_LENGTH is a bit too much, but it's only here as a reasonable end point
2810 int lastDescriptorNumber = (textLength + MAX_LEN-1) / MAX_LEN - 1;
2811 int remainingTextLength = textLength - lastDescriptorNumber * MAX_LEN;
2813 //if long description is too long, just try to fill as many descriptors as possible
2814 while ( (lastDescriptorNumber+1) * 256 + currentLoopLength > EIT_LENGTH - EIT_LOOP_SIZE)
2816 lastDescriptorNumber--;
2817 remainingTextLength = MAX_LEN;
2820 for (int descrIndex = 0; descrIndex <= lastDescriptorNumber; ++descrIndex)
2822 eit_extended_descriptor_struct *ext_evt = (eit_extended_descriptor_struct*) x;
2823 ext_evt->descriptor_tag = EIT_EXTENDED_EVENT_DESCRIPOR;
2824 //descriptor header length is 6, including the 2 tag and length bytes
2825 //so the length field must be: stringlength + 1 (2 4-bits numbers) + 3 (lang code) + 2 bytes for item info length field and text length field
2826 int currentTextLength = descrIndex < lastDescriptorNumber ? MAX_LEN : remainingTextLength;
2827 ext_evt->descriptor_length = 6 + currentTextLength + 1;
2829 ext_evt->descriptor_number = descrIndex;
2830 ext_evt->last_descriptor_number = lastDescriptorNumber;
2831 ext_evt->iso_639_2_language_code_1 = 'e';
2832 ext_evt->iso_639_2_language_code_2 = 'n';
2833 ext_evt->iso_639_2_language_code_3 = 'g';
2835 x[6] = 0; //item information (car, year, director, etc. Unsupported for now)
2836 x[7] = currentTextLength + 1; //length of description string (part in this message)
2838 memcpy(x + 9, &long_description[descrIndex*MAX_LEN], currentTextLength);
2840 x += 2 + ext_evt->descriptor_length;
2843 //TODO: add age and more
2844 int desc_loop_length = x - ((uint8_t*)evt_struct + EIT_LOOP_SIZE);
2845 evt_struct->setDescriptorsLoopLength(desc_loop_length);
2847 int packet_length = (x - data) - 3; //should add 1 for crc....
2848 packet->setSectionLength(packet_length);
2849 // Add channelrefs and submit data.
2850 for (unsigned int i = 0; i < chids.size(); i++)
2852 packet->setServiceId(sids[i]);
2853 packet->setTransportStreamId(chids[i].transport_stream_id.get());
2854 packet->setOriginalNetworkId(chids[i].original_network_id.get());
2855 sectionRead(data, source, 0);
2859 void eEPGCache::setEpgHistorySeconds(time_t seconds)
2861 historySeconds = seconds;
2864 void eEPGCache::setEpgSources(unsigned int mask)
2866 enabledSources = mask;
2869 unsigned int eEPGCache::getEpgSources()
2871 return enabledSources;
2874 static const char* getStringFromPython(ePyObject obj)
2877 if (PyString_Check(obj))
2879 result = PyString_AS_STRING(obj);
2884 void eEPGCache::importEvent(ePyObject serviceReference, ePyObject list)
2886 importEvents(serviceReference, list);
2889 //here we get a python tuple of tuples ;)
2890 // consider it an array of objects with the following data
2891 // 1. start time (long)
2892 // 2. duration (int)
2893 // 3. event title (string)
2894 // 4. short description (string)
2895 // 5. extended description (string)
2896 // 6. event type (byte)
2897 void eEPGCache::importEvents(ePyObject serviceReferences, ePyObject list)
2899 std::vector<eServiceReferenceDVB> refs;
2901 if (PyString_Check(serviceReferences))
2904 refstr = PyString_AS_STRING(serviceReferences);
2907 eDebug("[eEPGCache:import] serviceReference string is 0, aborting");
2910 refs.push_back(eServiceReferenceDVB(refstr));
2912 else if (PyList_Check(serviceReferences))
2914 int nRefs = PyList_Size(serviceReferences);
2915 for (int i = 0; i < nRefs; ++i)
2917 PyObject* item = PyList_GET_ITEM(serviceReferences, i);
2919 refstr = PyString_AS_STRING(item);
2922 eDebug("[eEPGCache:import] a serviceref item is not a string");
2926 refs.push_back(eServiceReferenceDVB(refstr));
2932 eDebug("[eEPGCache:import] serviceReference string is neither string nor list, aborting");
2936 bool isTuple = PyTuple_Check(list);
2937 if (!isTuple && !PyList_Check(list))
2940 eDebug("[eEPGCache:import] argument 'list' is neither list nor tuple.");
2944 int numberOfEvents = isTuple ? PyTuple_Size(list) : PyList_Size(list);
2946 for (int i = 0; i < numberOfEvents; ++i)
2948 ePyObject singleEvent = isTuple ? PyTuple_GET_ITEM(list, i) : PyList_GET_ITEM(list, i);
2949 if (!PyTuple_Check(singleEvent))
2951 eDebug("[eEPGCache:import] eventdata tuple does not pass PyTuple_Check, aborting");
2954 int tupleSize = PyTuple_Size(singleEvent);
2957 eDebug("[eEPGCache:import] eventdata tuple does not contain enough fields, aborting");
2961 long start = PyLong_AsLong(PyTuple_GET_ITEM(singleEvent, 0));
2962 long duration = PyInt_AsLong(PyTuple_GET_ITEM(singleEvent, 1));
2963 const char *title = getStringFromPython(PyTuple_GET_ITEM(singleEvent, 2));
2964 const char *short_summary = getStringFromPython(PyTuple_GET_ITEM(singleEvent, 3));
2965 const char *long_description = getStringFromPython(PyTuple_GET_ITEM(singleEvent, 4));
2966 char event_type = (char) PyInt_AsLong(PyTuple_GET_ITEM(singleEvent, 5));
2968 Py_BEGIN_ALLOW_THREADS;
2969 submitEventData(refs, start, duration, title, short_summary, long_description, event_type);
2970 Py_END_ALLOW_THREADS;
2974 // here we get a python tuple
2975 // the first entry in the tuple is a python string to specify the format of the returned tuples (in a list)
2977 // B = Event Begin Time
2978 // D = Event Duration
2980 // S = Event Short Description
2981 // P = Event Parental Rating
2982 // W = Event Content Description
2983 // E = Event Extended Description
2984 // R = Service Reference
2986 // n = Short Service Name
2987 // the second tuple entry is the MAX matches value
2988 // the third tuple entry is the type of query
2989 // 0 = search for similar broadcastings (SIMILAR_BROADCASTINGS_SEARCH)
2990 // 1 = search events with exactly title name (EXACT_TITLE_SEARCH)
2991 // 2 = search events with text in title name (PARTIAL_TITLE_SEARCH)
2992 // 3 = search events starting with title name (START_TITLE_SEARCH)
2993 // when type is 0 (SIMILAR_BROADCASTINGS_SEARCH)
2994 // the fourth is the servicereference string
2995 // the fifth is the eventid
2996 // when type > 0 (*_TITLE_SEARCH)
2997 // the fourth is the search text
2999 // 0 = case sensitive (CASE_CHECK)
3000 // 1 = case insensitive (NO_CASECHECK)
3002 PyObject *eEPGCache::search(ePyObject arg)
3005 std::deque<uint32_t> descr;
3007 const char *argstring=0;
3011 bool needServiceEvent=false;
3013 int must_get_service_name = 0;
3014 bool must_get_service_reference = false;
3016 if (PyTuple_Check(arg))
3018 int tuplesize=PyTuple_Size(arg);
3021 ePyObject obj = PyTuple_GET_ITEM(arg,0);
3022 if (PyString_Check(obj))
3024 #if PY_VERSION_HEX < 0x02060000
3025 argcount = PyString_GET_SIZE(obj);
3027 argcount = PyString_Size(obj);
3029 argstring = PyString_AS_STRING(obj);
3030 for (int i=0; i < argcount; ++i)
3032 switch(argstring[i])
3039 needServiceEvent=true;
3042 must_get_service_name = 1;
3045 must_get_service_name = 2;
3048 must_get_service_reference = true;
3057 PyErr_SetString(PyExc_StandardError,
3059 eDebug("[eEPGCache] tuple arg 0 is not a string");
3065 maxmatches = PyLong_AsLong(PyTuple_GET_ITEM(arg, 1));
3069 querytype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 2));
3071 if (tuplesize > 4 && querytype == 0)
3073 ePyObject obj = PyTuple_GET_ITEM(arg, 3);
3074 if (PyString_Check(obj))
3076 refstr = PyString_AS_STRING(obj);
3077 eServiceReferenceDVB ref(refstr);
3080 eventid = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4));
3081 singleLock s(cache_lock);
3082 const eventData *evData = 0;
3083 lookupEventId(ref, eventid, evData);
3086 // search short and extended event descriptors
3087 for (uint8_t i = 0; i < evData->n_crc; ++i)
3089 uint32_t crc = evData->crc_list[i];
3090 DescriptorMap::iterator it =
3091 eventData::descriptors.find(crc);
3092 if (it != eventData::descriptors.end())
3094 uint8_t *descr_data = it->second.data;
3095 switch(descr_data[0])
3098 descr.push_back(crc);
3107 eDebug("[eEPGCache] event not found");
3111 PyErr_SetString(PyExc_StandardError, "type error");
3112 eDebug("[eEPGCache] tuple arg 4 is not a valid service reference string");
3118 PyErr_SetString(PyExc_StandardError, "type error");
3119 eDebug("[eEPGCache] tuple arg 4 is not a string");
3123 else if (tuplesize > 4 && (querytype > 0) )
3125 ePyObject obj = PyTuple_GET_ITEM(arg, 3);
3126 if (PyString_Check(obj))
3128 int casetype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4));
3129 const char *str = PyString_AS_STRING(obj);
3130 #if PY_VERSION_HEX < 0x02060000
3131 int textlen = PyString_GET_SIZE(obj);
3133 int textlen = PyString_Size(obj);
3138 eDebug("[eEPGCache] lookup events with '%s' as title (%s)", str, casetype?"ignore case":"case sensitive");
3141 eDebug("[eEPGCache] lookup events with '%s' in title (%s)", str, casetype?"ignore case":"case sensitive");
3144 eDebug("[eEPGCache] lookup events, title starting with '%s' (%s)", str, casetype?"ignore case":"case sensitive");
3147 Py_BEGIN_ALLOW_THREADS; /* No Python code in this section, so other threads can run */
3148 singleLock s(cache_lock);
3150 for (DescriptorMap::iterator it(eventData::descriptors.begin());
3151 it != eventData::descriptors.end(); ++it)
3153 uint8_t *data = it->second.data;
3154 if ( data[0] == SHORT_EVENT_DESCRIPTOR )
3156 const char *titleptr = (const char*)&data[6];
3157 int title_len = data[5];
3160 /* custom encoding */
3161 title = convertDVBUTF8((unsigned char*)titleptr, title_len, 0x40, 0);
3162 titleptr = title.data();
3163 title_len = title.length();
3165 if (title_len < textlen)
3166 /*Doesn't fit, so cannot match anything */
3170 /* require exact title match */
3171 if (title_len != textlen)
3174 else if (querytype == 3)
3176 /* Do a "startswith" match by pretending the text isn't that long */
3177 title_len = textlen;
3181 while (title_len >= textlen)
3183 if (!strncasecmp(titleptr, str, textlen))
3185 descr.push_back(it->first);
3194 while (title_len >= textlen)
3196 if (!memcmp(titleptr, str, textlen))
3198 descr.push_back(it->first);
3207 Py_END_ALLOW_THREADS;
3211 PyErr_SetString(PyExc_StandardError,
3213 eDebug("[eEPGCache] tuple arg 4 is not a string");
3219 PyErr_SetString(PyExc_StandardError,
3221 eDebug("[eEPGCache] tuple arg 3(%d) is not a known querytype(0..3)", querytype);
3227 PyErr_SetString(PyExc_StandardError,
3229 eDebug("[eEPGCache] not enough args in tuple");
3235 PyErr_SetString(PyExc_StandardError,
3237 eDebug("[eEPGCache] arg 0 is not a tuple");
3243 int maxcount=maxmatches;
3244 eServiceReferenceDVB ref(refstr?(const eServiceReferenceDVB&)handleGroup(eServiceReference(refstr)):eServiceReferenceDVB(""));
3245 // ref is only valid in SIMILAR_BROADCASTING_SEARCH
3246 // in this case we start searching with the base service
3247 bool first = ref.valid() ? true : false;
3248 singleLock s(cache_lock);
3249 eventCache::iterator cit(ref.valid() ? eventDB.find(ref) : eventDB.begin());
3250 while(cit != eventDB.end() && maxcount)
3252 if ( ref.valid() && !first && cit->first == ref )
3254 // do not scan base service twice ( only in SIMILAR BROADCASTING SEARCH )
3258 timeMap &evmap = cit->second.byTime;
3260 for (timeMap::iterator evit(evmap.begin()); evit != evmap.end() && maxcount; ++evit)
3264 /* ignore the current event, when looking for similar events */
3265 if (evit->second->getEventID() == eventid)
3268 // check if any of our descriptor used by this event
3269 unsigned int cnt = 0;
3270 for (uint8_t i = 0; i < evit->second->n_crc; ++i)
3272 uint32_t crc32 = evit->second->crc_list[i];
3273 for (std::deque<uint32_t>::const_iterator it = descr.begin();
3274 it != descr.end(); ++it)
3276 if (*it == crc32) // found...
3281 /* we need only one match, when we're not looking for similar broadcasting events */
3282 i = evit->second->n_crc;
3288 if ( (querytype == 0 && cnt == descr.size()) ||
3289 ((querytype > 0) && cnt != 0) )
3291 const uniqueEPGKey &service = cit->first;
3292 std::vector<eServiceReference> refs;
3293 eDVBDB::getInstance()->searchAllReferences(refs, service.tsid, service.onid, service.sid);
3294 for (unsigned int i = 0; i < refs.size(); i++)
3296 eServiceReference ref = refs[i];
3299 ePyObject service_name;
3300 ePyObject service_reference;
3301 // create servive event
3303 const eventData *ev_data=0;
3304 if (needServiceEvent)
3306 if (lookupEventId(ref, evit->second->getEventID(), ev_data))
3307 eDebug("[eEPGCache] event not found !!!!!!!!!!!");
3310 const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref;
3311 Event ev((uint8_t*)ev_data->get());
3312 ptr.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get());
3315 // create service name
3316 if (must_get_service_name && !service_name)
3318 ePtr<iStaticServiceInformation> sptr;
3319 eServiceCenterPtr service_center;
3320 eServiceCenter::getPrivInstance(service_center);
3323 service_center->info(ref, sptr);
3327 sptr->getName(ref, name);
3329 if (must_get_service_name == 1)
3332 // filter short name brakets
3333 while((pos = name.find("\xc2\x86")) != std::string::npos)
3335 while((pos = name.find("\xc2\x87")) != std::string::npos)
3339 name = buildShortName(name);
3342 service_name = PyString_FromString(name.c_str());
3346 service_name = PyString_FromString("<n/a>");
3348 // create servicereference string
3349 if (must_get_service_reference && !service_reference)
3350 service_reference = PyString_FromString(ref.toString().c_str());
3353 ret = PyList_New(0);
3355 ePyObject tuple = PyTuple_New(argcount);
3357 ePyObject tmp = ePyObject();
3358 fillTuple(tuple, argstring, argcount, service_reference, ev_data ? &ptr : 0, service_name, tmp, evit->second);
3359 PyList_Append(ret, tuple);
3362 Py_DECREF(service_name);
3363 if (service_reference)
3364 Py_DECREF(service_reference);
3372 // now start at first service in epgcache database ( only in SIMILAR BROADCASTING SEARCH )
3374 cit=eventDB.begin();
3387 #ifdef ENABLE_PRIVATE_EPG
3388 #include <dvbsi++/descriptor_tag.h>
3389 #include <dvbsi++/unknown_descriptor.h>
3390 #include <dvbsi++/private_data_specifier_descriptor.h>
3392 void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler)
3394 ePtr<eTable<ProgramMapSection> > ptr;
3395 if (!pmthandler->getPMT(ptr) && ptr)
3397 std::vector<ProgramMapSection*>::const_iterator i;
3398 for (i = ptr->getSections().begin(); i != ptr->getSections().end(); ++i)
3400 const ProgramMapSection &pmt = **i;
3402 ElementaryStreamInfoConstIterator es;
3403 for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es)
3406 switch ((*es)->getType())
3408 case 0xC1: // user private
3409 for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
3410 desc != (*es)->getDescriptors()->end(); ++desc)
3412 switch ((*desc)->getTag())
3414 case 0xC2: // user defined
3415 if ((*desc)->getLength() == 8)
3418 (*desc)->writeToBuffer(buffer);
3419 if (!memcmp((const char *)buffer+2, "EPGDATA", 7))
3421 eServiceReferenceDVB ref;
3422 if (!pmthandler->getServiceReference(ref))
3424 int pid = (*es)->getPid();
3425 messages.send(Message(Message::got_mhw2_channel_pid, ref, pid));
3428 else if(!memcmp((const char *)buffer+2, "FICHAS", 6))
3430 eServiceReferenceDVB ref;
3431 if (!pmthandler->getServiceReference(ref))
3433 int pid = (*es)->getPid();
3434 messages.send(Message(Message::got_mhw2_summary_pid, ref, pid));
3437 else if(!memcmp((const char *)buffer+2, "GENEROS", 7))
3439 eServiceReferenceDVB ref;
3440 if (!pmthandler->getServiceReference(ref))
3442 int pid = (*es)->getPid();
3443 messages.send(Message(Message::got_mhw2_title_pid, ref, pid));
3452 case 0x05: // private
3453 for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
3454 desc != (*es)->getDescriptors()->end(); ++desc)
3456 switch ((*desc)->getTag())
3458 case PRIVATE_DATA_SPECIFIER_DESCRIPTOR:
3459 if (((PrivateDataSpecifierDescriptor*)(*desc))->getPrivateDataSpecifier() == 190)
3464 Descriptor *descr = (Descriptor*)*desc;
3465 int descr_len = descr->getLength();
3468 uint8_t data[descr_len+2];
3469 descr->writeToBuffer(data);
3470 if ( !data[2] && !data[3] && data[4] == 0xFF && data[5] == 0xFF )
3484 eServiceReferenceDVB ref;
3485 if (!pmthandler->getServiceReference(ref))
3487 int pid = (*es)->getPid();
3488 messages.send(Message(Message::got_private_pid, ref, pid));
3496 eDebug("[eEPGCache] PMTready but no pmt!!");
3503 date_time( const date_time &a )
3505 memcpy(data, a.data, 5);
3508 date_time( const uint8_t data[5])
3510 memcpy(this->data, data, 5);
3511 tm = parseDVBtime(data);
3516 const uint8_t& operator[](int pos) const
3522 struct less_datetime
3524 bool operator()( const date_time &a, const date_time &b ) const
3526 return abs(a.tm-b.tm) < 360 ? false : a.tm < b.tm;
3530 void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const uint8_t *data)
3532 contentMap &content_time_table = content_time_tables[current_service];
3533 singleLock s(cache_lock);
3534 std::map< date_time, std::list<uniqueEPGKey>, less_datetime > start_times;
3535 EventCacheItem &eventDBitem = eventDB[current_service];
3536 eventMap &evMap = eventDBitem.byEvent;
3537 timeMap &tmMap = eventDBitem.byTime;
3539 int content_id = data[ptr++] << 24;
3540 content_id |= data[ptr++] << 16;
3541 content_id |= data[ptr++] << 8;
3542 content_id |= data[ptr++];
3544 contentTimeMap &time_event_map = content_time_table[content_id];
3545 for ( contentTimeMap::iterator it( time_event_map.begin() );
3546 it != time_event_map.end(); ++it )
3548 eventMap::iterator evIt( evMap.find(it->second.second) );
3549 if ( evIt != evMap.end() )
3551 // time_event_map can have other timestamp -> get timestamp from eventData
3552 time_t ev_time = evIt->second->getStartTime();
3553 delete evIt->second;
3555 tmMap.erase(ev_time);
3558 time_event_map.clear();
3560 uint8_t duration[3];
3561 memcpy(duration, data+ptr, 3);
3564 fromBCD(duration[0])*3600+fromBCD(duration[1])*60+fromBCD(duration[2]);
3566 const uint8_t *descriptors[65];
3567 const uint8_t **pdescr = descriptors;
3569 int descriptors_length = (data[ptr++]&0x0F) << 8;
3570 descriptors_length |= data[ptr++];
3571 while ( descriptors_length > 1 )
3573 int descr_type = data[ptr];
3574 int descr_len = data[ptr+1];
3575 descriptors_length -= 2;
3576 if (descriptors_length >= descr_len)
3578 descriptors_length -= descr_len;
3579 if ( descr_type == 0xf2 && descr_len > 5)
3582 int tsid = data[ptr++] << 8;
3583 tsid |= data[ptr++];
3584 int onid = data[ptr++] << 8;
3585 onid |= data[ptr++];
3586 int sid = data[ptr++] << 8;
3589 // WORKAROUND for wrong transmitted epg data (01.10.2007)
3592 switch( (tsid << 16) | sid )
3594 case 0x01030b: sid = 0x1b; tsid = 4; break; // Premiere Win
3595 case 0x0300f0: sid = 0xe0; tsid = 2; break;
3596 case 0x0300f1: sid = 0xe1; tsid = 2; break;
3597 case 0x0300f5: sid = 0xdc; break;
3598 case 0x0400d2: sid = 0xe2; tsid = 0x11; break;
3599 case 0x1100d3: sid = 0xe3; break;
3600 case 0x0100d4: sid = 0xe4; tsid = 4; break;
3603 ////////////////////////////////////////////
3605 uniqueEPGKey service( sid, onid, tsid );
3607 while( descr_len > 2 )
3609 uint8_t datetime[5];
3610 datetime[0] = data[ptr++];
3611 datetime[1] = data[ptr++];
3612 int tmp_len = data[ptr++];
3614 if (descr_len >= tmp_len)
3616 descr_len -= tmp_len;
3617 while( tmp_len > 2 )
3619 memcpy(datetime+2, data+ptr, 3);
3622 start_times[datetime].push_back(service);
3635 ASSERT(pdescr <= &descriptors[65]);
3636 uint8_t event[4098];
3637 eit_event_struct *ev_struct = (eit_event_struct*) event;
3638 ev_struct->running_status = 0;
3639 ev_struct->free_CA_mode = 1;
3640 memcpy(event+7, duration, 3);
3642 const uint8_t **d=descriptors;
3643 while ( d < pdescr )
3645 memcpy(event+ptr, *d, ((*d)[1])+2);
3649 ASSERT(ptr <= 4098);
3650 for ( std::map< date_time, std::list<uniqueEPGKey> >::iterator it(start_times.begin()); it != start_times.end(); ++it )
3652 time_t now = ::time(0);
3653 if ( (it->first.tm + duration_sec) < now )
3655 memcpy(event+2, it->first.data, 5);
3658 for (std::list<uniqueEPGKey>::iterator i(it->second.begin()); i != it->second.end(); ++i)
3660 event[bptr++] = 0x4A;
3661 uint8_t *len = event+(bptr++);
3662 event[bptr++] = (i->tsid & 0xFF00) >> 8;
3663 event[bptr++] = (i->tsid & 0xFF);
3664 event[bptr++] = (i->onid & 0xFF00) >> 8;
3665 event[bptr++] = (i->onid & 0xFF);
3666 event[bptr++] = (i->sid & 0xFF00) >> 8;
3667 event[bptr++] = (i->sid & 0xFF);
3668 event[bptr++] = 0xB0;
3669 bptr += sprintf((char*)(event+bptr), "Option %d", ++cnt);
3670 *len = ((event+bptr) - len)-1;
3672 int llen = bptr - 12;
3673 ev_struct->descriptors_loop_length_hi = (llen & 0xF00) >> 8;
3674 ev_struct->descriptors_loop_length_lo = (llen & 0xFF);
3676 time_t stime = it->first.tm;
3677 while( tmMap.find(stime) != tmMap.end() )
3679 event[6] += (stime - it->first.tm);
3680 uint16_t event_id = 0;
3681 while( evMap.find(event_id) != evMap.end() )
3683 event[0] = (event_id & 0xFF00) >> 8;
3684 event[1] = (event_id & 0xFF);
3685 time_event_map[it->first.tm]=std::pair<time_t, uint16_t>(stime, event_id);
3686 eventData *d = new eventData( ev_struct, bptr, PRIVATE );
3687 evMap[event_id] = d;
3689 ASSERT(bptr <= 4098);
3693 void eEPGCache::channel_data::startPrivateReader()
3695 eDVBSectionFilterMask mask;
3696 memset(&mask, 0, sizeof(mask));
3697 mask.pid = m_PrivatePid;
3698 mask.flags = eDVBSectionFilterMask::rfCRC;
3699 mask.data[0] = 0xA0;
3700 mask.mask[0] = 0xFF;
3701 eDebug("[eEPGCache] start privatefilter for pid %04x and version %d", m_PrivatePid, m_PrevVersion);
3702 if (m_PrevVersion != -1)
3704 mask.data[3] = m_PrevVersion << 1;
3705 mask.mask[3] = 0x3E;
3706 mask.mode[3] = 0x3E;
3708 seenPrivateSections.clear();
3710 m_PrivateReader->connectRead(slot(*this, &eEPGCache::channel_data::readPrivateData), m_PrivateConn);
3711 m_PrivateReader->start(mask);
3714 void eEPGCache::channel_data::readPrivateData( const uint8_t *data)
3716 if ( seenPrivateSections.find(data[6]) == seenPrivateSections.end() )
3718 cache->privateSectionRead(m_PrivateService, data);
3719 seenPrivateSections.insert(data[6]);
3721 if ( seenPrivateSections.size() == (unsigned int)(data[7] + 1) )
3723 eDebug("[eEPGCache] private finished");
3724 eDVBChannelID chid = channel->getChannelID();
3725 int tmp = chid.original_network_id.get();
3726 tmp |= 0x80000000; // we use highest bit as private epg indicator
3727 chid.original_network_id = tmp;
3728 cache->channelLastUpdated[chid] = ::time(0);
3729 m_PrevVersion = (data[5] & 0x3E) >> 1;
3730 startPrivateReader();
3734 #endif // ENABLE_PRIVATE_EPG
3736 #ifdef ENABLE_MHW_EPG
3737 void eEPGCache::channel_data::cleanupMHW()
3739 m_MHWTimeoutTimer->stop();
3743 m_program_ids.clear();
3746 uint8_t *eEPGCache::channel_data::delimitName( uint8_t *in, uint8_t *out, int len_in )
3748 // Names in mhw structs are not strings as they are not '\0' terminated.
3749 // This function converts the mhw name into a string.
3750 // Constraint: "length of out" = "length of in" + 1.
3752 for ( i=0; i < len_in; i++ )
3756 while ( ( i >=0 ) && ( out[i] == 0x20 ) )
3763 void eEPGCache::channel_data::timeMHW2DVB( u_char hours, u_char minutes, u_char *return_time)
3766 return_time[0] = toBCD( hours );
3767 return_time[1] = toBCD( minutes );
3771 void eEPGCache::channel_data::timeMHW2DVB( int minutes, u_char *return_time)
3773 timeMHW2DVB( int(minutes/60), minutes%60, return_time );
3776 void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minutes, u_char *return_time)
3777 // For date plus time of day
3779 char tz_saved[1024];
3780 // Remove offset in mhw time.
3781 uint8_t local_hours = hours;
3784 else if ( hours >= 8 )
3787 // As far as we know all mhw time data is sent in central Europe time zone.
3788 // So, temporarily set timezone to western europe
3789 time_t dt = ::time(0);
3791 char *old_tz = getenv( "TZ" );
3793 strcpy(tz_saved, old_tz);
3794 putenv((char*)"TZ=CET-1CEST,M3.5.0/2,M10.5.0/3");
3798 localtime_r(&dt, &localnow);
3802 if ( day + 1 < localnow.tm_wday ) // day + 1 to prevent old events to show for next week.
3804 if (local_hours <= 5)
3807 dt += 3600*24*(day - localnow.tm_wday); // Shift dt to the recording date (local time zone).
3808 dt += 3600*(local_hours - localnow.tm_hour); // Shift dt to the recording hour.
3811 gmtime_r( &dt, &recdate ); // This will also take care of DST.
3813 if ( old_tz == NULL )
3816 setenv("TZ", tz_saved, 1);
3819 // Calculate MJD according to annex in ETSI EN 300 468
3821 if ( recdate.tm_mon <= 1 ) // Jan or Feb
3823 int mjd = 14956 + recdate.tm_mday + int( (recdate.tm_year - l) * 365.25) +
3824 int( (recdate.tm_mon + 2 + l * 12) * 30.6001);
3826 return_time[0] = (mjd & 0xFF00)>>8;
3827 return_time[1] = mjd & 0xFF;
3829 timeMHW2DVB( recdate.tm_hour, minutes, return_time+2 );
3832 void eEPGCache::channel_data::storeMHWTitle(std::map<uint32_t, mhw_title_t>::iterator itTitle, std::string sumText, const uint8_t *data)
3833 // data is borrowed from calling proc to save memory space.
3837 // For each title a separate EIT packet will be sent to eEPGCache::sectionRead()
3838 bool isMHW2 = itTitle->second.mhw2_mjd_hi || itTitle->second.mhw2_mjd_lo ||
3839 itTitle->second.mhw2_duration_hi || itTitle->second.mhw2_duration_lo;
3841 eit_t *packet = (eit_t *) data;
3842 packet->table_id = 0x50;
3843 packet->section_syntax_indicator = 1;
3845 packet->service_id_hi = m_channels[ itTitle->second.channel_id - 1 ].channel_id_hi;
3846 packet->service_id_lo = m_channels[ itTitle->second.channel_id - 1 ].channel_id_lo;
3847 packet->version_number = 0; // eEPGCache::sectionRead() will dig this for the moment
3848 packet->current_next_indicator = 0;
3849 packet->section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
3850 packet->last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
3851 packet->transport_stream_id_hi = m_channels[ itTitle->second.channel_id - 1 ].transport_stream_id_hi;
3852 packet->transport_stream_id_lo = m_channels[ itTitle->second.channel_id - 1 ].transport_stream_id_lo;
3853 packet->original_network_id_hi = m_channels[ itTitle->second.channel_id - 1 ].network_id_hi;
3854 packet->original_network_id_lo = m_channels[ itTitle->second.channel_id - 1 ].network_id_lo;
3855 packet->segment_last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment
3856 packet->segment_last_table_id = 0x50;
3858 uint8_t *title = isMHW2 ? ((uint8_t*)(itTitle->second.title))-4 : (uint8_t*)itTitle->second.title;
3859 std::string prog_title = (char *) delimitName( title, name, isMHW2 ? 35 : 23 );
3860 int prog_title_length = prog_title.length();
3862 int packet_length = EIT_SIZE + EIT_LOOP_SIZE + EIT_SHORT_EVENT_DESCRIPTOR_SIZE +
3863 prog_title_length + 1;
3865 eit_event_t *event_data = (eit_event_t *) (data + EIT_SIZE);
3866 event_data->event_id_hi = (( itTitle->first ) >> 8 ) & 0xFF;
3867 event_data->event_id_lo = ( itTitle->first ) & 0xFF;
3871 u_char *data = (u_char*) event_data;
3872 data[2] = itTitle->second.mhw2_mjd_hi;
3873 data[3] = itTitle->second.mhw2_mjd_lo;
3874 data[4] = itTitle->second.mhw2_hours;
3875 data[5] = itTitle->second.mhw2_minutes;
3876 data[6] = itTitle->second.mhw2_seconds;
3877 timeMHW2DVB( itTitle->second.getMhw2Duration(), data+7 );
3881 timeMHW2DVB( itTitle->second.dh.day, itTitle->second.dh.hours, itTitle->second.ms.minutes,
3882 (u_char *) event_data + 2 );
3883 timeMHW2DVB( itTitle->second.getDuration(), (u_char *) event_data+7 );
3886 event_data->running_status = 0;
3887 event_data->free_CA_mode = 0;
3888 int descr_ll = EIT_SHORT_EVENT_DESCRIPTOR_SIZE + 1 + prog_title_length;
3890 eit_short_event_descriptor_struct *short_event_descriptor =
3891 (eit_short_event_descriptor_struct *) ( (u_char *) event_data + EIT_LOOP_SIZE);
3892 short_event_descriptor->descriptor_tag = EIT_SHORT_EVENT_DESCRIPTOR;
3893 short_event_descriptor->descriptor_length = EIT_SHORT_EVENT_DESCRIPTOR_SIZE +
3894 prog_title_length - 1;
3895 short_event_descriptor->language_code_1 = 'e';
3896 short_event_descriptor->language_code_2 = 'n';
3897 short_event_descriptor->language_code_3 = 'g';
3898 short_event_descriptor->event_name_length = prog_title_length;
3899 u_char *event_name = (u_char *) short_event_descriptor + EIT_SHORT_EVENT_DESCRIPTOR_SIZE;
3900 memcpy(event_name, prog_title.c_str(), prog_title_length);
3903 event_name[prog_title_length] = 0;
3905 if ( sumText.length() > 0 )
3906 // There is summary info
3908 unsigned int sum_length = sumText.length();
3909 if ( sum_length + short_event_descriptor->descriptor_length <= 0xff )
3910 // Store summary in short event descriptor
3912 // Increase all relevant lengths
3913 event_name[prog_title_length] = sum_length;
3914 short_event_descriptor->descriptor_length += sum_length;
3915 packet_length += sum_length;
3916 descr_ll += sum_length;
3917 sumText.copy( (char *) event_name+prog_title_length+1, sum_length );
3920 // Store summary in extended event descriptors
3922 int remaining_sum_length = sumText.length();
3923 int nbr_descr = int(remaining_sum_length/247) + 1;
3924 for ( int i=0; i < nbr_descr; i++)
3925 // Loop once per extended event descriptor
3927 eit_extended_descriptor_struct *ext_event_descriptor = (eit_extended_descriptor_struct *) (data + packet_length);
3928 sum_length = remaining_sum_length > 247 ? 247 : remaining_sum_length;
3929 remaining_sum_length -= sum_length;
3930 packet_length += 8 + sum_length;
3931 descr_ll += 8 + sum_length;
3933 ext_event_descriptor->descriptor_tag = EIT_EXTENDED_EVENT_DESCRIPOR;
3934 ext_event_descriptor->descriptor_length = sum_length + 6;
3935 ext_event_descriptor->descriptor_number = i;
3936 ext_event_descriptor->last_descriptor_number = nbr_descr - 1;
3937 ext_event_descriptor->iso_639_2_language_code_1 = 'e';
3938 ext_event_descriptor->iso_639_2_language_code_2 = 'n';
3939 ext_event_descriptor->iso_639_2_language_code_3 = 'g';
3940 u_char *the_text = (u_char *) ext_event_descriptor + 8;
3942 the_text[-1] = sum_length;
3943 sumText.copy( (char *) the_text, sum_length, sumText.length() - sum_length - remaining_sum_length );
3950 // Add content descriptor
3951 u_char *descriptor = (u_char *) data + packet_length;
3956 std::string content_descr = (char *) delimitName( m_themes[itTitle->second.theme_id].name, name, 15 );
3957 if ( content_descr.find( "FILM" ) != std::string::npos )
3959 else if ( content_descr.find( "SPORT" ) != std::string::npos )
3962 descriptor[0] = 0x54;
3964 descriptor[2] = content_id;
3968 event_data->descriptors_loop_length_hi = (descr_ll & 0xf00)>>8;
3969 event_data->descriptors_loop_length_lo = (descr_ll & 0xff);
3971 packet->section_length_hi = ((packet_length - 3)&0xf00)>>8;
3972 packet->section_length_lo = (packet_length - 3)&0xff;
3974 // Feed the data to eEPGCache::sectionRead()
3975 cache->sectionRead( data, MHW, this );
3978 void eEPGCache::channel_data::startMHWTimeout(int msec)
3980 m_MHWTimeoutTimer->start(msec,true);
3981 m_MHWTimeoutet=false;
3984 void eEPGCache::channel_data::startMHWReader(uint16_t pid, uint8_t tid)
3986 m_MHWFilterMask.pid = pid;
3987 m_MHWFilterMask.data[0] = tid;
3988 m_MHWReader->start(m_MHWFilterMask);
3989 // eDebug("[eEPGCache] start 0x%02x 0x%02x", pid, tid);
3992 void eEPGCache::channel_data::startMHWReader2(uint16_t pid, uint8_t tid, int ext)
3994 m_MHWFilterMask2.pid = pid;
3995 m_MHWFilterMask2.data[0] = tid;
3998 m_MHWFilterMask2.data[1] = ext;
3999 m_MHWFilterMask2.mask[1] = 0xFF;
4000 // eDebug("[eEPGCache] start 0x%03x 0x%02x 0x%02x", pid, tid, ext);
4004 m_MHWFilterMask2.data[1] = 0;
4005 m_MHWFilterMask2.mask[1] = 0;
4006 // eDebug("[eEPGCache] start 0x%02x 0x%02x", pid, tid);
4008 m_MHWReader2->start(m_MHWFilterMask2);
4011 void eEPGCache::channel_data::readMHWData(const uint8_t *data)
4014 m_MHWReader2->stop();
4016 if ( state > 1 || // aborted
4017 // have si data.. so we dont read mhw data
4018 (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) )
4020 eDebug("[eEPGCache] mhw aborted %d", state);
4022 else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x91)
4025 int len = ((data[1]&0xf)<<8) + data[2] - 1;
4026 int record_size = sizeof( mhw_channel_name_t );
4027 int nbr_records = int (len/record_size);
4029 m_channels.resize(nbr_records);
4030 for ( int i = 0; i < nbr_records; i++ )
4032 mhw_channel_name_t *channel = (mhw_channel_name_t*) &data[4 + i*record_size];
4033 m_channels[i]=*channel;
4037 eDebug("[eEPGCache] mhw %d channels found", m_channels.size());
4039 // Channels table has been read, start reading the themes table.
4040 startMHWReader(0xD3, 0x92);
4043 else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x92)
4046 int len = ((data[1]&0xf)<<8) + data[2] - 16;
4047 int record_size = sizeof( mhw_theme_name_t );
4048 int nbr_records = int (len/record_size);
4050 uint8_t next_idx = (uint8_t) *(data + 3 + idx_ptr);
4052 uint8_t sub_idx = 0;
4053 for ( int i = 0; i < nbr_records; i++ )
4055 mhw_theme_name_t *theme = (mhw_theme_name_t*) &data[19 + i*record_size];
4056 if ( i >= next_idx )
4060 next_idx = (uint8_t) *(data + 3 + idx_ptr);
4066 m_themes[idx+sub_idx] = *theme;
4068 eDebug("[eEPGCache] mhw %d themes found", m_themes.size());
4069 // Themes table has been read, start reading the titles table.
4070 startMHWReader(0xD2, 0x90);
4071 startMHWTimeout(4000);
4074 else if (m_MHWFilterMask.pid == 0xD2 && m_MHWFilterMask.data[0] == 0x90)
4077 mhw_title_t *title = (mhw_title_t*) data;
4079 std::string prog_title = (char *) delimitName( title->title, name, 23 );
4081 if ( title->channel_id == 0xFF || prog_title.substr(0,7) == "BIENTOT" ) // Separator or BIENTOT record
4082 return; // Continue reading of the current table.
4085 // Create unique key per title
4086 uint32_t title_id = ((title->channel_id)<<16)|((title->dh.day)<<13)|((title->dh.hours)<<8)|
4087 (title->ms.minutes);
4088 uint32_t program_id = ((title->program_id_hi)<<24)|((title->program_id_mh)<<16)|
4089 ((title->program_id_ml)<<8)|(title->program_id_lo);
4091 if ( m_titles.find( title_id ) == m_titles.end() )
4093 startMHWTimeout(4000);
4094 title->mhw2_mjd_hi = 0;
4095 title->mhw2_mjd_lo = 0;
4096 title->mhw2_duration_hi = 0;
4097 title->mhw2_duration_lo = 0;
4098 m_titles[ title_id ] = *title;
4099 if ( (title->ms.summary_available) && (m_program_ids.find(program_id) == m_program_ids.end()) )
4100 // program_ids will be used to gather summaries.
4101 m_program_ids.insert(std::pair<uint32_t,uint32_t>(program_id,title_id));
4102 return; // Continue reading of the current table.
4104 else if (!checkMHWTimeout())
4107 if ( !m_program_ids.empty())
4109 // Titles table has been read, there are summaries to read.
4110 // Start reading summaries, store corresponding titles on the fly.
4111 startMHWReader(0xD3, 0x90);
4112 eDebug("[eEPGCache] mhw %d titles(%d with summary) found",
4114 m_program_ids.size());
4115 startMHWTimeout(4000);
4119 else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x90)
4122 mhw_summary_t *summary = (mhw_summary_t*) data;
4124 // Create unique key per record
4125 uint32_t program_id = ((summary->program_id_hi)<<24)|((summary->program_id_mh)<<16)|
4126 ((summary->program_id_ml)<<8)|(summary->program_id_lo);
4127 int len = ((data[1]&0xf)<<8) + data[2];
4129 // ugly workaround to convert const uint8_t* to char*
4131 memcpy(&tmp, &data, sizeof(void*));
4132 tmp[len+3] = 0; // Terminate as a string.
4134 std::multimap<uint32_t, uint32_t>::iterator itProgid( m_program_ids.find( program_id ) );
4135 if ( itProgid == m_program_ids.end() )
4136 { /* This part is to prevent to looping forever if some summaries are not received yet.
4137 There is a timeout of 4 sec. after the last successfully read summary. */
4138 if (!m_program_ids.empty() && !checkMHWTimeout())
4139 return; // Continue reading of the current table.
4143 std::string the_text = (char *) (data + 11 + summary->nb_replays * 7);
4146 while((pos = the_text.find("\r\n")) != std::string::npos)
4147 the_text.replace(pos, 2, " ");
4149 // Find corresponding title, store title and summary in epgcache.
4150 std::map<uint32_t, mhw_title_t>::iterator itTitle( m_titles.find( itProgid->second ) );
4151 if ( itTitle != m_titles.end() )
4153 startMHWTimeout(4000);
4154 storeMHWTitle( itTitle, the_text, data );
4155 m_titles.erase( itTitle );
4157 m_program_ids.erase( itProgid );
4158 if ( !m_program_ids.empty() )
4159 return; // Continue reading of the current table.
4162 eDebug("[eEPGCache] mhw finished(%ld) %d summaries not found",
4164 m_program_ids.size());
4165 // Summaries have been read, titles that have summaries have been stored.
4166 // Now store titles that do not have summaries.
4167 for (std::map<uint32_t, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++)
4168 storeMHWTitle( itTitle, "", data );
4172 m_MHWReader->stop();
4177 void eEPGCache::channel_data::readMHWData2(const uint8_t *data)
4179 int dataLen = (((data[1]&0xf) << 8) | data[2]) + 3;
4182 m_MHWReader->stop();
4184 if ( state > 1 || // aborted
4185 // have si data.. so we dont read mhw data
4186 (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) )
4188 eDebug("[eEPGCache] mhw2 aborted %d", state);
4190 else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
4193 int num_channels = data[120];
4194 m_channels.resize(num_channels);
4197 int ptr = 121 + 8 * num_channels;
4200 for( int chid = 0; chid < num_channels; ++chid )
4202 ptr += ( data[ptr] & 0x0f ) + 1;
4212 // data seems consistent...
4213 const uint8_t *tmp = data+121;
4214 for (int i=0; i < num_channels; ++i)
4216 mhw_channel_name_t channel;
4217 channel.network_id_hi = *(tmp++);
4218 channel.network_id_lo = *(tmp++);
4219 channel.transport_stream_id_hi = *(tmp++);
4220 channel.transport_stream_id_lo = *(tmp++);
4221 channel.channel_id_hi = *(tmp++);
4222 channel.channel_id_lo = *(tmp++);
4223 m_channels[i]=channel;
4224 // eDebug("[eEPGCache] %d(%02x) %04x: %02x %02x", i, i, (channel.channel_id_hi << 8) | channel.channel_id_lo, *tmp, *(tmp+1));
4227 for (int i=0; i < num_channels; ++i)
4229 mhw_channel_name_t &channel = m_channels[i];
4230 int channel_name_len=*(tmp++)&0x0f;
4232 for (; x < channel_name_len; ++x)
4233 channel.name[x]=*(tmp++);
4234 channel.name[x+1]=0;
4235 // eDebug("[eEPGCache] %d(%02x) %s", i, i, channel.name);
4238 eDebug("[eEPGCache] mhw2 %d channels found", m_channels.size());
4240 else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1)
4243 eDebug("[eEPGCache] mhw2 themes nyi");
4245 else if (m_MHWFilterMask2.pid == m_mhw2_title_pid && m_MHWFilterMask2.data[0] == 0xe6)
4252 // eDebug("[eEPGCache] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
4253 // data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10],
4254 // data[11], data[12], data[13], data[14], data[15], data[16], data[17] );
4256 while( pos < dataLen && !valid)
4259 pos += (data[pos] & 0x3F) + 4;
4260 if( pos == dataLen )
4267 eDebug("[eEPGCache] mhw2 title table invalid!!");
4268 if (checkMHWTimeout())
4270 if (!m_MHWTimeoutTimer->isActive())
4271 startMHWTimeout(5000);
4272 return; // continue reading
4275 // data seems consistent...
4278 while (pos < dataLen)
4280 // eDebugNoNewLine("[eEPGCache] [%02x] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x [%02x %02x %02x %02x %02x %02x %02x] LL - DESCR - ",
4281 // data[pos], data[pos+1], data[pos+2], data[pos+3], data[pos+4], data[pos+5], data[pos+6], data[pos+7],
4282 // data[pos+8], data[pos+9], data[pos+10], data[pos+11], data[pos+12], data[pos+13], data[pos+14], data[pos+15], data[pos+16], data[pos+17]);
4283 title.channel_id = data[pos]+1;
4284 title.mhw2_mjd_hi = data[pos+11];
4285 title.mhw2_mjd_lo = data[pos+12];
4286 title.mhw2_hours = data[pos+13];
4287 title.mhw2_minutes = data[pos+14];
4288 title.mhw2_seconds = data[pos+15];
4289 int duration = ((data[pos+16] << 8)|data[pos+17]) >> 4;
4290 title.mhw2_duration_hi = (duration&0xFF00) >> 8;
4291 title.mhw2_duration_lo = duration&0xFF;
4293 // Create unique key per title
4294 uint32_t title_id = (data[pos+7] << 24) | (data[pos+8] << 16) | (data[pos+9] << 8) | data[pos+10];
4296 uint8_t slen = data[pos+18] & 0x3f;
4297 uint8_t *dest = ((uint8_t*)title.title)-4;
4298 memcpy(dest, &data[pos+19], slen>35 ? 35 : slen);
4299 memset(dest+slen, 0, 35-slen);
4301 // eDebug("%02x [%02x %02x]: %s", data[pos], data[pos+1], data[pos+2], dest);
4303 // not used theme id (data[7] & 0x3f) + (data[pos] & 0x3f);
4304 uint32_t summary_id = (data[pos+1] << 8) | data[pos+2];
4306 // if (title.channel_id > m_channels.size())
4307 // eDebug("[eEPGCache] channel_id(%d %02x) to big!!", title.channel_id);
4309 // eDebug("[eEPGCache] pos %d prog_id %02x %02x chid %02x summary_id %04x dest %p len %d\n",
4310 // pos, title.program_id_ml, title.program_id_lo, title.channel_id, summary_id, dest, slen);
4312 // eDebug("[eEPGCache] title_id %08x -> summary_id %04x\n", title_id, summary_id);
4316 std::map<uint32_t, mhw_title_t>::iterator it = m_titles.find( title_id );
4317 if ( it == m_titles.end() )
4319 startMHWTimeout(5000);
4320 m_titles[ title_id ] = title;
4321 if (summary_id != 0xFFFF)
4324 std::multimap<uint32_t, uint32_t>::iterator it(m_program_ids.lower_bound(summary_id));
4325 while (it != m_program_ids.end() && it->first == summary_id)
4327 if (it->second == title_id) {
4334 m_program_ids.insert(std::pair<uint32_t,uint32_t>(summary_id,title_id));
4339 if ( !checkMHWTimeout() )
4340 continue; // Continue reading of the current table.
4347 eDebug("[eEPGCache] mhw2 %d titles(%d with summary) found", m_titles.size(), m_program_ids.size());
4348 if (!m_program_ids.empty())
4350 // Titles table has been read, there are summaries to read.
4351 // Start reading summaries, store corresponding titles on the fly.
4352 startMHWReader2(m_mhw2_summary_pid, 0x96);
4353 startMHWTimeout(15000);
4360 else if (m_MHWFilterMask2.pid == m_mhw2_summary_pid && m_MHWFilterMask2.data[0] == 0x96)
4363 if (!checkMHWTimeout())
4365 int len, loop, pos, lenline;
4374 loop = data[pos] & 0x0f;
4379 for( ; loop > 0; --loop )
4381 if( dataLen > (pos+len) )
4383 lenline = data[pos+len];
4393 return; // continue reading
4397 // data seems consistent...
4398 uint32_t summary_id = (data[3]<<8)|data[4];
4399 // eDebug ("[eEPGCache] summary id %04x\n", summary_id);
4400 // eDebug("[eEPGCache] [%02x %02x] %02x %02x %02x %02x %02x %02x %02x %02x XX\n", data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13] );
4402 // ugly workaround to convert const uint8_t* to char*
4404 memcpy(&tmp, &data, sizeof(void*));
4409 loop = tmp[pos] & 0x0f;
4411 for( ; loop > 0; loop -- )
4413 lenline = tmp[pos+len];
4422 std::multimap<uint32_t, uint32_t>::iterator itProgId( m_program_ids.lower_bound(summary_id) );
4423 if ( itProgId == m_program_ids.end() || itProgId->first != summary_id)
4424 { /* This part is to prevent to looping forever if some summaries are not received yet.
4425 There is a timeout of 4 sec. after the last successfully read summary. */
4426 if ( !m_program_ids.empty() )
4427 return; // Continue reading of the current table.
4431 startMHWTimeout(15000);
4432 std::string the_text = (char *) (data + pos + 1);
4434 // eDebug ("[eEPGCache] summary id %04x : %s\n", summary_id, data+pos+1);
4436 while( itProgId != m_program_ids.end() && itProgId->first == summary_id )
4438 // eDebug("[eEPGCache] .");
4439 // Find corresponding title, store title and summary in epgcache.
4440 std::map<uint32_t, mhw_title_t>::iterator itTitle( m_titles.find( itProgId->second ) );
4441 if ( itTitle != m_titles.end() )
4443 storeMHWTitle( itTitle, the_text, data );
4444 m_titles.erase( itTitle );
4446 m_program_ids.erase( itProgId++ );
4448 if ( !m_program_ids.empty() )
4449 return; // Continue reading of the current table.
4453 return; // continue reading
4456 if (isRunning & eEPGCache::MHW)
4458 if ( m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
4460 // Channels table has been read, start reading the themes table.
4461 startMHWReader2(m_mhw2_channel_pid, 0xC8, 1);
4464 else if ( m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1)
4466 // Themes table has been read, start reading the titles table.
4467 startMHWReader2(m_mhw2_title_pid, 0xe6);
4472 // Summaries have been read, titles that have summaries have been stored.
4473 // Now store titles that do not have summaries.
4474 for (std::map<uint32_t, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++)
4475 storeMHWTitle( itTitle, "", data );
4476 eDebug("[eEPGCache] mhw2 finished(%ld) %d summaries not found",
4478 m_program_ids.size());
4485 m_MHWReader2->stop();