+void eEPGCache::channel_data::startTimeout(int msec)
+{
+ m_MHWTimeoutTimer->start(msec,true);
+ m_MHWTimeoutet=false;
+}
+
+void eEPGCache::channel_data::startMHWReader(__u16 pid, __u8 tid)
+{
+ m_MHWFilterMask.pid = pid;
+ m_MHWFilterMask.data[0] = tid;
+ m_MHWReader->start(m_MHWFilterMask);
+// eDebug("start 0x%02x 0x%02x", pid, tid);
+}
+
+void eEPGCache::channel_data::startMHWReader2(__u16 pid, __u8 tid, int ext)
+{
+ m_MHWFilterMask2.pid = pid;
+ m_MHWFilterMask2.data[0] = tid;
+ if (ext != -1)
+ {
+ m_MHWFilterMask2.data[1] = ext;
+ m_MHWFilterMask2.mask[1] = 0xFF;
+// eDebug("start 0x%03x 0x%02x 0x%02x", pid, tid, ext);
+ }
+ else
+ {
+ m_MHWFilterMask2.data[1] = 0;
+ m_MHWFilterMask2.mask[1] = 0;
+// eDebug("start 0x%02x 0x%02x", pid, tid);
+ }
+ m_MHWReader2->start(m_MHWFilterMask2);
+}
+
+void eEPGCache::channel_data::readMHWData(const __u8 *data)
+{
+ if ( m_MHWReader2 )
+ m_MHWReader2->stop();
+
+ if ( state > 1 || // aborted
+ // have si data.. so we dont read mhw data
+ (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) )
+ {
+ eDebug("[EPGC] mhw aborted %d", state);
+ }
+ else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x91)
+ // Channels table
+ {
+ int len = ((data[1]&0xf)<<8) + data[2] - 1;
+ int record_size = sizeof( mhw_channel_name_t );
+ int nbr_records = int (len/record_size);
+
+ m_channels.resize(nbr_records);
+ for ( int i = 0; i < nbr_records; i++ )
+ {
+ mhw_channel_name_t *channel = (mhw_channel_name_t*) &data[4 + i*record_size];
+ m_channels[i]=*channel;
+ }
+ haveData |= MHW;
+
+ eDebug("[EPGC] mhw %d channels found", m_channels.size());
+
+ // Channels table has been read, start reading the themes table.
+ startMHWReader(0xD3, 0x92);
+ return;
+ }
+ else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x92)
+ // Themes table
+ {
+ int len = ((data[1]&0xf)<<8) + data[2] - 16;
+ int record_size = sizeof( mhw_theme_name_t );
+ int nbr_records = int (len/record_size);
+ int idx_ptr = 0;
+ __u8 next_idx = (__u8) *(data + 3 + idx_ptr);
+ __u8 idx = 0;
+ __u8 sub_idx = 0;
+ for ( int i = 0; i < nbr_records; i++ )
+ {
+ mhw_theme_name_t *theme = (mhw_theme_name_t*) &data[19 + i*record_size];
+ if ( i >= next_idx )
+ {
+ idx = (idx_ptr<<4);
+ idx_ptr++;
+ next_idx = (__u8) *(data + 3 + idx_ptr);
+ sub_idx = 0;
+ }
+ else
+ sub_idx++;
+
+ m_themes[idx+sub_idx] = *theme;
+ }
+ eDebug("[EPGC] mhw %d themes found", m_themes.size());
+ // Themes table has been read, start reading the titles table.
+ startMHWReader(0xD2, 0x90);
+ startTimeout(4000);
+ return;
+ }
+ else if (m_MHWFilterMask.pid == 0xD2 && m_MHWFilterMask.data[0] == 0x90)
+ // Titles table
+ {
+ mhw_title_t *title = (mhw_title_t*) data;
+
+ if ( title->channel_id == 0xFF ) // Separator
+ return; // Continue reading of the current table.
+ else
+ {
+ // Create unique key per title
+ __u32 title_id = ((title->channel_id)<<16)|((title->dh.day)<<13)|((title->dh.hours)<<8)|
+ (title->ms.minutes);
+ __u32 program_id = ((title->program_id_hi)<<24)|((title->program_id_mh)<<16)|
+ ((title->program_id_ml)<<8)|(title->program_id_lo);
+
+ if ( m_titles.find( title_id ) == m_titles.end() )
+ {
+ startTimeout(4000);
+ title->mhw2_mjd_hi = 0;
+ title->mhw2_mjd_lo = 0;
+ title->mhw2_duration_hi = 0;
+ title->mhw2_duration_lo = 0;
+ m_titles[ title_id ] = *title;
+ if ( (title->ms.summary_available) && (m_program_ids.find(program_id) == m_program_ids.end()) )
+ // program_ids will be used to gather summaries.
+ m_program_ids.insert(std::pair<__u32,__u32>(program_id,title_id));
+ return; // Continue reading of the current table.
+ }
+ else if (!checkTimeout())
+ return;
+ }
+ if ( !m_program_ids.empty())
+ {
+ // Titles table has been read, there are summaries to read.
+ // Start reading summaries, store corresponding titles on the fly.
+ startMHWReader(0xD3, 0x90);
+ eDebug("[EPGC] mhw %d titles(%d with summary) found",
+ m_titles.size(),
+ m_program_ids.size());
+ startTimeout(4000);
+ return;
+ }
+ }
+ else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x90)
+ // Summaries table
+ {
+ mhw_summary_t *summary = (mhw_summary_t*) data;
+
+ // Create unique key per record
+ __u32 program_id = ((summary->program_id_hi)<<24)|((summary->program_id_mh)<<16)|
+ ((summary->program_id_ml)<<8)|(summary->program_id_lo);
+ int len = ((data[1]&0xf)<<8) + data[2];
+
+ // ugly workaround to convert const __u8* to char*
+ char *tmp=0;
+ memcpy(&tmp, &data, sizeof(void*));
+ tmp[len+3] = 0; // Terminate as a string.
+
+ std::multimap<__u32, __u32>::iterator itProgid( m_program_ids.find( program_id ) );
+ if ( itProgid == m_program_ids.end() )
+ { /* This part is to prevent to looping forever if some summaries are not received yet.
+ There is a timeout of 4 sec. after the last successfully read summary. */
+ if (!m_program_ids.empty() && !checkTimeout())
+ return; // Continue reading of the current table.
+ }
+ else
+ {
+ std::string the_text = (char *) (data + 11 + summary->nb_replays * 7);
+
+ unsigned int pos=0;
+ while((pos = the_text.find("\r\n")) != std::string::npos)
+ the_text.replace(pos, 2, " ");
+
+ // Find corresponding title, store title and summary in epgcache.
+ std::map<__u32, mhw_title_t>::iterator itTitle( m_titles.find( itProgid->second ) );
+ if ( itTitle != m_titles.end() )
+ {
+ startTimeout(4000);
+ storeTitle( itTitle, the_text, data );
+ m_titles.erase( itTitle );
+ }
+ m_program_ids.erase( itProgid );
+ if ( !m_program_ids.empty() )
+ return; // Continue reading of the current table.
+ }
+ }
+ eDebug("[EPGC] mhw finished(%ld) %d summaries not found",
+ ::time(0),
+ m_program_ids.size());
+ // Summaries have been read, titles that have summaries have been stored.
+ // Now store titles that do not have summaries.
+ for (std::map<__u32, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++)
+ storeTitle( itTitle, "", data );
+ isRunning &= ~MHW;
+ m_MHWConn=0;
+ if ( m_MHWReader )
+ m_MHWReader->stop();
+ if (haveData)
+ finishEPG();
+}
+
+void eEPGCache::channel_data::readMHWData2(const __u8 *data)
+{
+ int dataLen = (((data[1]&0xf) << 8) | data[2]) + 3;
+
+ if ( m_MHWReader )
+ m_MHWReader->stop();
+
+ if ( state > 1 || // aborted
+ // have si data.. so we dont read mhw data
+ (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) )
+ {
+ eDebug("[EPGC] mhw2 aborted %d", state);
+ }
+ else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
+ // Channels table
+ {
+ int num_channels = data[120];
+ m_channels.resize(num_channels);
+ if(dataLen > 120)
+ {
+ int ptr = 121 + 8 * num_channels;
+ if( dataLen > ptr )
+ {
+ for( int chid = 0; chid < num_channels; ++chid )
+ {
+ ptr += ( data[ptr] & 0x0f ) + 1;
+ if( dataLen < ptr )
+ goto abort;
+ }
+ }
+ else
+ goto abort;
+ }
+ else
+ goto abort;
+ // data seems consistent...
+ const __u8 *tmp = data+121;
+ for (int i=0; i < num_channels; ++i)
+ {
+ mhw_channel_name_t channel;
+ channel.network_id_hi = *(tmp++);
+ channel.network_id_lo = *(tmp++);
+ channel.transport_stream_id_hi = *(tmp++);
+ channel.transport_stream_id_lo = *(tmp++);
+ channel.channel_id_hi = *(tmp++);
+ channel.channel_id_lo = *(tmp++);
+ m_channels[i]=channel;
+// eDebug("%d(%02x) %04x: %02x %02x", i, i, (channel.channel_id_hi << 8) | channel.channel_id_lo, *tmp, *(tmp+1));
+ tmp+=2;
+ }
+ for (int i=0; i < num_channels; ++i)
+ {
+ mhw_channel_name_t &channel = m_channels[i];
+ int channel_name_len=*(tmp++)&0x0f;
+ int x=0;
+ for (; x < channel_name_len; ++x)
+ channel.name[x]=*(tmp++);
+ channel.name[x+1]=0;
+// eDebug("%d(%02x) %s", i, i, channel.name);
+ }
+ haveData |= MHW;
+ eDebug("[EPGC] mhw2 %d channels found", m_channels.size());
+ }
+ else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1)
+ {
+ // Themes table
+ eDebug("[EPGC] mhw2 themes nyi");
+ }
+ else if (m_MHWFilterMask2.pid == m_mhw2_title_pid && m_MHWFilterMask2.data[0] == 0xe6)
+ // Titles table
+ {
+ int pos=18;
+ bool valid=false;
+ bool finish=false;
+
+// eDebug("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+// data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10],
+// data[11], data[12], data[13], data[14], data[15], data[16], data[17] );
+
+ while( pos < dataLen && !valid)
+ {
+ pos += 18;
+ pos += (data[pos] & 0x3F) + 4;
+ if( pos == dataLen )
+ valid = true;
+ }
+
+ if (!valid)
+ {
+ if (dataLen > 18)
+ eDebug("mhw2 title table invalid!!");
+ if (checkTimeout())
+ goto abort;
+ if (!m_MHWTimeoutTimer->isActive())
+ startTimeout(5000);
+ return; // continue reading
+ }
+
+ // data seems consistent...
+ mhw_title_t title;
+ pos = 18;
+ while (pos < dataLen)
+ {
+// eDebugNoNewLine(" [%02x] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x [%02x %02x %02x %02x %02x %02x %02x] LL - DESCR - ",
+// data[pos], data[pos+1], data[pos+2], data[pos+3], data[pos+4], data[pos+5], data[pos+6], data[pos+7],
+// 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]);
+ title.channel_id = data[pos]+1;
+ title.mhw2_mjd_hi = data[pos+11];
+ title.mhw2_mjd_lo = data[pos+12];
+ title.mhw2_hours = data[pos+13];
+ title.mhw2_minutes = data[pos+14];
+ title.mhw2_seconds = data[pos+15];
+ int duration = ((data[pos+16] << 8)|data[pos+17]) >> 4;
+ title.mhw2_duration_hi = (duration&0xFF00) >> 8;
+ title.mhw2_duration_lo = duration&0xFF;
+
+ // Create unique key per title
+ __u32 title_id = (data[pos+7] << 24) | (data[pos+8] << 16) | (data[pos+9] << 8) | data[pos+10];
+
+ __u8 slen = data[pos+18] & 0x3f;
+ __u8 *dest = ((__u8*)title.title)-4;
+ memcpy(dest, &data[pos+19], slen>35 ? 35 : slen);
+ memset(dest+slen, 0, 35-slen);
+ pos += 19 + slen;
+// eDebug("%02x [%02x %02x]: %s", data[pos], data[pos+1], data[pos+2], dest);
+
+// not used theme id (data[7] & 0x3f) + (data[pos] & 0x3f);
+ __u32 summary_id = (data[pos+1] << 8) | data[pos+2];
+
+// if (title.channel_id > m_channels.size())
+// eDebug("channel_id(%d %02x) to big!!", title.channel_id);
+
+// eDebug("pos %d prog_id %02x %02x chid %02x summary_id %04x dest %p len %d\n",
+// pos, title.program_id_ml, title.program_id_lo, title.channel_id, summary_id, dest, slen);
+
+// eDebug("title_id %08x -> summary_id %04x\n", title_id, summary_id);
+
+ pos += 3;
+
+ std::map<__u32, mhw_title_t>::iterator it = m_titles.find( title_id );
+ if ( it == m_titles.end() )
+ {
+ startTimeout(5000);
+ m_titles[ title_id ] = title;
+ if (summary_id != 0xFFFF)
+ {
+ bool add=true;
+ std::multimap<__u32, __u32>::iterator it(m_program_ids.lower_bound(summary_id));
+ while (it != m_program_ids.end() && it->first == summary_id)
+ {
+ if (it->second == title_id) {
+ add=false;
+ break;
+ }
+ ++it;
+ }
+ if (add)
+ m_program_ids.insert(std::pair<__u32,__u32>(summary_id,title_id));
+ }
+ }
+ else
+ {
+ if ( !checkTimeout() )
+ continue; // Continue reading of the current table.
+ finish=true;
+ break;
+ }
+ }
+start_summary:
+ if (finish)
+ {
+ eDebug("[EPGC] mhw2 %d titles(%d with summary) found", m_titles.size(), m_program_ids.size());
+ if (!m_program_ids.empty())
+ {
+ // Titles table has been read, there are summaries to read.
+ // Start reading summaries, store corresponding titles on the fly.
+ startMHWReader2(m_mhw2_summary_pid, 0x96);
+ startTimeout(15000);
+ return;
+ }
+ }
+ else
+ return;
+ }
+ else if (m_MHWFilterMask2.pid == m_mhw2_summary_pid && m_MHWFilterMask2.data[0] == 0x96)
+ // Summaries table
+ {
+ if (!checkTimeout())
+ {
+ int len, loop, pos, lenline;
+ bool valid;
+ valid = true;
+ if( dataLen > 15 )
+ {
+ loop = data[14];
+ pos = 15 + loop;
+ if( dataLen > pos )
+ {
+ loop = data[pos] & 0x0f;
+ pos += 1;
+ if( dataLen > pos )
+ {
+ len = 0;
+ for( ; loop > 0; --loop )
+ {
+ if( dataLen > (pos+len) )
+ {
+ lenline = data[pos+len];
+ len += lenline + 1;
+ }
+ else
+ valid=false;
+ }
+ }
+ }
+ }
+ else
+ return; // continue reading
+
+ if (valid)
+ {
+ // data seems consistent...
+ __u32 summary_id = (data[3]<<8)|data[4];
+// eDebug ("summary id %04x\n", summary_id);
+// eDebug("[%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] );
+
+ // ugly workaround to convert const __u8* to char*
+ char *tmp=0;
+ memcpy(&tmp, &data, sizeof(void*));
+
+ len = 0;
+ loop = data[14];
+ pos = 15 + loop;
+ loop = tmp[pos] & 0x0f;
+ pos += 1;
+ for( ; loop > 0; loop -- )
+ {
+ lenline = tmp[pos+len];
+ tmp[pos+len] = ' ';
+ len += lenline + 1;
+ }
+ if( len > 0 )
+ tmp[pos+len] = 0;
+ else
+ tmp[pos+1] = 0;
+
+ std::multimap<__u32, __u32>::iterator itProgId( m_program_ids.lower_bound(summary_id) );
+ if ( itProgId == m_program_ids.end() || itProgId->first != summary_id)
+ { /* This part is to prevent to looping forever if some summaries are not received yet.
+ There is a timeout of 4 sec. after the last successfully read summary. */
+ if ( !m_program_ids.empty() )
+ return; // Continue reading of the current table.
+ }
+ else
+ {
+ startTimeout(15000);
+ std::string the_text = (char *) (data + pos + 1);
+
+// eDebug ("summary id %04x : %s\n", summary_id, data+pos+1);
+
+ while( itProgId != m_program_ids.end() && itProgId->first == summary_id )
+ {
+// eDebug(".");
+ // Find corresponding title, store title and summary in epgcache.
+ std::map<__u32, mhw_title_t>::iterator itTitle( m_titles.find( itProgId->second ) );
+ if ( itTitle != m_titles.end() )
+ {
+ storeTitle( itTitle, the_text, data );
+ m_titles.erase( itTitle );
+ }
+ m_program_ids.erase( itProgId++ );
+ }
+ if ( !m_program_ids.empty() )
+ return; // Continue reading of the current table.
+ }
+ }
+ else
+ return; // continue reading
+ }
+ }
+ if (isRunning & eEPGCache::MHW)
+ {
+ if ( m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0)
+ {
+ // Channels table has been read, start reading the themes table.
+ startMHWReader2(m_mhw2_channel_pid, 0xC8, 1);
+ return;
+ }
+ else if ( m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1)
+ {
+ // Themes table has been read, start reading the titles table.
+ startMHWReader2(m_mhw2_title_pid, 0xe6);
+ return;
+ }
+ else
+ {
+ // Summaries have been read, titles that have summaries have been stored.
+ // Now store titles that do not have summaries.
+ for (std::map<__u32, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++)
+ storeTitle( itTitle, "", data );
+ eDebug("[EPGC] mhw2 finished(%ld) %d summaries not found",
+ ::time(0),
+ m_program_ids.size());
+ }
+ }
+abort:
+ isRunning &= ~MHW;
+ m_MHWConn2=0;
+ if ( m_MHWReader2 )
+ m_MHWReader2->stop();
+ if (haveData)
+ finishEPG();
+}
+#endif