add missing files, add ability to specify table_id mask and table_id ext mask
authorAndreas Monzner <andreas.monzner@multimedia-labs.de>
Sat, 2 Jul 2005 09:27:18 +0000 (09:27 +0000)
committerAndreas Monzner <andreas.monzner@multimedia-labs.de>
Sat, 2 Jul 2005 09:27:18 +0000 (09:27 +0000)
lib/dvb/dvbtime.cpp [new file with mode: 0644]
lib/dvb/dvbtime.h [new file with mode: 0644]
lib/dvb/esection.cpp
lib/dvb/idemux.h
lib/dvb/isection.h

diff --git a/lib/dvb/dvbtime.cpp b/lib/dvb/dvbtime.cpp
new file mode 100644 (file)
index 0000000..84a1ef4
--- /dev/null
@@ -0,0 +1,407 @@
+#include <lib/dvb/dvbtime.h>
+#include <lib/dvb/dvb.h>
+
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+// defines for DM7000 / DM7020
+#define FP_IOCTL_SET_RTC         0x101
+#define FP_IOCTL_GET_RTC         0x102
+
+static time_t prev_time;
+
+void setRTC(time_t time)
+{
+       int fd = open("/dev/dbox/fp0", O_RDWR);
+       if ( fd >= 0 )
+       {
+               if ( ::ioctl(fd, FP_IOCTL_SET_RTC, (void*)&time ) < 0 )
+                       eDebug("FP_IOCTL_SET_RTC failed(%m)");
+               else
+                       prev_time = time;
+               close(fd);
+       }
+}
+
+time_t getRTC()
+{
+       time_t rtc_time=0;
+       int fd = open("/dev/dbox/fp0", O_RDWR);
+       if ( fd >= 0 )
+       {
+               if ( ::ioctl(fd, FP_IOCTL_GET_RTC, (void*)&rtc_time ) < 0 )
+                       eDebug("FP_IOCTL_GET_RTC failed(%m)");
+               close(fd);
+       }
+       return rtc_time != prev_time ? rtc_time : 0;
+}
+
+int fromBCD(int bcd)
+{
+       if ((bcd&0xF0)>=0xA0)
+               return -1;
+       if ((bcd&0xF)>=0xA)
+               return -1;
+       return ((bcd&0xF0)>>4)*10+(bcd&0xF);
+}
+
+time_t parseDVBtime(__u8 t1, __u8 t2, __u8 t3, __u8 t4, __u8 t5)
+{
+       tm t;
+       t.tm_sec=fromBCD(t5);
+       t.tm_min=fromBCD(t4);
+       t.tm_hour=fromBCD(t3);
+       int mjd=(t1<<8)|t2;
+       int k;
+
+       t.tm_year = (int) ((mjd - 15078.2) / 365.25);
+       t.tm_mon = (int) ((mjd - 14956.1 - (int)(t.tm_year * 365.25)) / 30.6001);
+       t.tm_mday = (int) (mjd - 14956 - (int)(t.tm_year * 365.25) - (int)(t.tm_mon * 30.6001));
+       k = (t.tm_mon == 14 || t.tm_mon == 15) ? 1 : 0;
+       t.tm_year = t.tm_year + k;
+       t.tm_mon = t.tm_mon - 1 - k * 12;
+       t.tm_mon--;
+
+       t.tm_isdst =  0;
+       t.tm_gmtoff = 0;
+
+       return timegm(&t);
+}
+
+TDT::TDT(eDVBChannel *chan)
+       :chan(chan)
+{
+       CONNECT(tableReady, TDT::ready);
+       CONNECT(m_interval_timer.timeout, TDT::start);
+       if (chan)
+               chan->getDemux(demux);
+}
+
+void TDT::ready(int error)
+{
+       eDVBLocalTimeHandler::getInstance()->updateTime(error, chan);
+}
+
+int TDT::createTable(int nr, const __u8 *data, unsigned int max)
+{
+       if ( data && data[0] == 0x70 || data[0] == 0x73 )
+       {
+               int length = ((data[1] & 0x0F) << 8) | data[2];
+               if ( length >= 8 )
+               {
+                       time_t tptime = parseDVBtime(data[3], data[4], data[5], data[6], data[7]);
+                       eDVBLocalTimeHandler::getInstance()->updateTime(tptime, chan);
+                       error=0;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+void TDT::start()
+{
+       if ( chan )
+       {
+               eDVBTableSpec spec;
+               spec.pid = TimeAndDateTable::PID;
+               spec.tid = TimeAndDateTable::TID;
+               spec.tid_mask = 0xFC;
+               spec.timeout = TimeAndDateTable::TIMEOUT;
+               spec.flags= eDVBTableSpec::tfAnyVersion |
+                                       eDVBTableSpec::tfHaveTID |
+                                       eDVBTableSpec::tfHaveTIDMask |
+                                       eDVBTableSpec::tfCheckCRC |
+                                       eDVBTableSpec::tfHaveTimeout;
+               if ( demux )
+                       eGTable::start( demux, spec );
+       }
+}
+
+void TDT::startTimer( int interval )
+{
+       m_interval_timer.start(interval, true);
+}
+
+eDVBLocalTimeHandler *eDVBLocalTimeHandler::instance;
+DEFINE_REF(eDVBLocalTimeHandler);
+
+eDVBLocalTimeHandler::eDVBLocalTimeHandler()
+       :m_time_ready(false), m_time_difference(0)
+{
+       if ( !instance )
+               instance=this;
+       ePtr<eDVBResourceManager> res_mgr;
+       eDVBResourceManager::getInstance(res_mgr);
+       if (!res_mgr)
+               eDebug("[eDVBLocalTimerHandler] no resource manager !!!!!!!");
+       else
+       {
+               res_mgr->connectChannelAdded(slot(*this,&eDVBLocalTimeHandler::DVBChannelAdded), m_chanAddedConn);
+               res_mgr->connectChannelRemoved(slot(*this,&eDVBLocalTimeHandler::DVBChannelRemoved), m_chanRemovedConn);
+               res_mgr->connectChannelRunning(slot(*this,&eDVBLocalTimeHandler::DVBChannelRunning), m_chanRunningConn);
+       }
+}
+
+eDVBLocalTimeHandler::~eDVBLocalTimeHandler()
+{
+       instance=0;
+       for (std::map<iDVBChannel*, TDT*>::iterator it=m_active_tables.begin(); it != m_active_tables.end(); ++it)
+               delete it->second;
+}
+
+void eDVBLocalTimeHandler::readTimeOffsetData( const char* filename )
+{
+       m_timeOffsetMap.clear();
+       FILE *f=fopen(filename, "r");
+       if (!f)
+               return;
+       char line[256];
+       fgets(line, 256, f);
+       while (true)
+       {
+               if (!fgets( line, 256, f ))
+                       break;
+               if (strstr(line, "Transponder UTC Time Offsets\n"))
+                       continue;
+               int dvbnamespace,tsid,onid,offs;
+               if ( sscanf( line, "%08x,%04x,%04x:%d\n",&dvbnamespace,&tsid,&onid,&offs ) == 4 )
+                       m_timeOffsetMap[eDVBChannelID(dvbnamespace,tsid,onid)]=offs;
+       }
+       fclose(f);
+}
+
+void eDVBLocalTimeHandler::writeTimeOffsetData( const char* filename )
+{
+       FILE *f=fopen(filename, "w+");
+       if ( f )
+       {
+               fprintf(f, "Transponder UTC Time Offsets\n");
+               for ( std::map<eDVBChannelID,int>::iterator it ( m_timeOffsetMap.begin() ); it != m_timeOffsetMap.end(); ++it )
+                       fprintf(f, "%08x,%04x,%04x:%d\n",
+                               it->first.dvbnamespace.get(),
+                               it->first.transport_stream_id.get(), it->first.original_network_id.get(), it->second );
+               fclose(f);
+       }
+}
+
+void eDVBLocalTimeHandler::updateTime( time_t tp_time, eDVBChannel *chan )
+{
+       bool restart_tdt = false;
+       if (!tp_time )
+               restart_tdt = true;
+       else if (tp_time == -1)
+       {
+               restart_tdt = true;
+               /*if ( eSystemInfo::getInstance()->getHwType() == eSystemInfo::DM7020 ||
+               ( eSystemInfo::getInstance()->getHwType() == eSystemInfo::DM7000
+                       && eSystemInfo::getInstance()->hasStandbyWakeupTimer() ) )     TODO !!!!!!! */
+               {
+                       eDebug("[eDVBLocalTimerHandler] no transponder tuned... or no TDT/TOT avail .. try to use RTC :)");
+                       time_t rtc_time = getRTC();
+                       if ( rtc_time ) // RTC Ready?
+                       {
+                               tm now = *localtime(&rtc_time);
+                               eDebug("[eDVBLocalTimerHandler] RTC time is %02d:%02d:%02d",
+                                       now.tm_hour,
+                                       now.tm_min,
+                                       now.tm_sec);
+                               time_t linuxTime=time(0);
+                               time_t nowTime=linuxTime+m_time_difference;
+                               now = *localtime(&nowTime);
+                               eDebug("[eDVBLocalTimerHandler] Receiver time is %02d:%02d:%02d",
+                                       now.tm_hour,
+                                       now.tm_min,
+                                       now.tm_sec);
+                               m_time_difference = rtc_time - linuxTime;
+                               eDebug("[eDVBLocalTimerHandler] RTC to Receiver time difference is %d seconds", nowTime - rtc_time );
+                               if ( abs(m_time_difference) > 59 )
+                               {
+                                       eDebug("[eDVBLocalTimerHandler] set Linux Time to RTC Time");
+                                       timeval tnow;
+                                       gettimeofday(&tnow,0);
+                                       tnow.tv_sec=rtc_time;
+                                       settimeofday(&tnow,0);
+                                       for (ePtrList<eMainloop>::iterator it(eMainloop::existing_loops)
+                                               ;it != eMainloop::existing_loops.end(); ++it)
+                                               it->setTimerOffset(m_time_difference);
+                                       m_time_difference=0;
+                               }
+                               else if ( !m_time_difference )
+                                       eDebug("[eDVBLocalTimerHandler] no change needed");
+                               else
+                                       eDebug("[eDVBLocalTimerHandler] set to RTC time");
+                               /*emit*/ m_timeUpdated();
+                       }
+                       else
+                               eDebug("[eDVBLocalTimerHandler] shit RTC not ready :(");
+               }
+       }
+       else
+       {
+               std::map< eDVBChannelID, int >::iterator it( m_timeOffsetMap.find( chan->getChannelID() ) );
+
+ // current linux time
+               time_t linuxTime = time(0);
+
+ // current enigma time
+               time_t nowTime=linuxTime+m_time_difference;
+
+       // difference between current enigma time and transponder time
+               int enigma_diff = tp_time-nowTime;
+
+               int new_diff=0;
+
+               if ( m_time_ready )  // ref time ready?
+               {
+                       // difference between reference time (current enigma time)
+                       // and the transponder time
+                       eDebug("[eDVBLocalTimerHandler] diff is %d", enigma_diff);
+                       if ( abs(enigma_diff) < 120 )
+                       {
+                               eDebug("[eDVBLocalTimerHandler] diff < 120 .. use Transponder Time");
+                               m_timeOffsetMap[chan->getChannelID()] = 0;
+                               new_diff = enigma_diff;
+                       }
+                       else if ( it != m_timeOffsetMap.end() ) // correction saved?
+                       {
+                               eDebug("[eDVBLocalTimerHandler] we have correction %d", it->second);
+                               time_t CorrectedTpTime = tp_time+it->second;
+                               int ddiff = CorrectedTpTime-nowTime;
+                               eDebug("[eDVBLocalTimerHandler] diff after add correction is %d", ddiff);
+                               if ( abs(it->second) < 300 ) // stored correction < 5 min
+                               {
+                                       eDebug("[eDVBLocalTimerHandler] use stored correction(<5 min)");
+                                       new_diff = ddiff;
+                               }
+                               else if ( /*eSystemInfo::getInstance()->getHwType() == eSystemInfo::DM7020 &&  TODO !!!*/
+                                               getRTC() )
+                               {
+                                       time_t rtc=getRTC();
+                                       m_timeOffsetMap[chan->getChannelID()] = rtc-tp_time;
+                                       new_diff = rtc-nowTime;  // set enigma time to rtc
+                                       eDebug("[eDVBLocalTimerHandler] update stored correction to %d (calced against RTC time)", rtc-tp_time );
+                               }
+                               else if ( abs(ddiff) <= 120 )
+                               {
+// with stored correction calced time difference is lower 2 min
+// this don't help when a transponder have a clock running to slow or to fast
+// then its better to have a DM7020 with always running RTC
+                                       eDebug("[eDVBLocalTimerHandler] use stored correction(corr < 2 min)");
+                                       new_diff = ddiff;
+                               }
+                               else  // big change in calced correction.. hold current time and update correction
+                               {
+                                       eDebug("[eDVBLocalTimerHandler] update stored correction to %d", -enigma_diff);
+                                       m_timeOffsetMap[chan->getChannelID()] = -enigma_diff;
+                               }
+                       }
+                       else
+                       {
+                               eDebug("[eDVBLocalTimerHandler] no correction found... store calced correction(%d)",-enigma_diff);
+                               m_timeOffsetMap[chan->getChannelID()] = -enigma_diff;
+                       }
+               }
+               else  // no time setted yet
+               {
+                       if ( it != m_timeOffsetMap.end() )
+                       {
+                               enigma_diff += it->second;
+                               eDebug("[eDVBLocalTimerHandler] we have correction (%d)... use", it->second );
+                       }
+                       else
+                               eDebug("[eDVBLocalTimerHandler] dont have correction.. set Transponder Diff");
+                       new_diff=enigma_diff;
+                       m_time_ready=true;
+               }
+
+               time_t t = nowTime+new_diff;
+               m_last_tp_time_difference=tp_time-t;
+
+               if (!new_diff)
+               {
+                       eDebug("[eDVBLocalTimerHandler] not changed");
+                       return;
+               }
+
+               tm now = *localtime(&t);
+               eDebug("[eDVBLocalTimerHandler] time update to %02d:%02d:%02d",
+                       now.tm_hour,
+                       now.tm_min,
+                       now.tm_sec);
+
+               m_time_difference = t - linuxTime;   // calc our new linux_time -> enigma_time correction
+               eDebug("[eDVBLocalTimerHandler] m_time_difference is %d", m_time_difference );
+
+//             if ( eSystemInfo::getInstance()->getHwType() == eSystemInfo::DM7020 )  TODO !!
+                       setRTC(t);
+
+               if ( abs(m_time_difference) > 59 )
+               {
+                       eDebug("[eDVBLocalTimerHandler] set Linux Time");
+                       timeval tnow;
+                       gettimeofday(&tnow,0);
+                       tnow.tv_sec=t;
+                       settimeofday(&tnow,0);
+                       for (ePtrList<eMainloop>::iterator it(eMainloop::existing_loops)
+                               ;it != eMainloop::existing_loops.end(); ++it)
+                               it->setTimerOffset(m_time_difference);
+                       m_time_difference=0;
+               }
+
+                /*emit*/ m_timeUpdated();
+       }
+
+       if ( restart_tdt )
+       {
+               std::map<iDVBChannel*, TDT*>::iterator it =
+                       m_active_tables.find(chan);
+               if ( it != m_active_tables.end() )
+               {
+                       delete it->second;
+                       it->second = new TDT(chan);
+                       it->second->startTimer(60*60*1000);  // restart TDT for this transponder in 60min
+               }
+       }
+
+}
+
+void eDVBLocalTimeHandler::DVBChannelAdded(eDVBChannel *chan)
+{
+       eDebug("[eDVBLocalTimerHandler] add channel %p", chan);
+       if ( chan )
+       {
+               std::map<iDVBChannel*, TDT*>::iterator it =
+                       m_active_tables.find(chan);
+               if ( it != m_active_tables.end() )
+               {
+                       delete it->second;
+                       it->second = new TDT(chan);
+               }
+               else
+                       m_active_tables[chan] = new TDT(chan);
+       }
+}
+
+void eDVBLocalTimeHandler::DVBChannelRemoved(eDVBChannel *chan)
+{
+       eDebug("[eDVBLocalTimerHandler] remove channel %p", chan);
+       std::map<iDVBChannel*, TDT*>::iterator it =
+               m_active_tables.find(chan);
+       if ( it != m_active_tables.end() )
+       {
+               delete it->second;
+               m_active_tables.erase(it);
+       }
+}
+
+void eDVBLocalTimeHandler::DVBChannelRunning(iDVBChannel *chan)
+{
+       eDebug("[eDVBLocalTimerHandler] start channel %p", chan);
+       std::map<iDVBChannel*, TDT*>::iterator it =
+               m_active_tables.find(chan);
+       if ( it != m_active_tables.end() )
+               it->second->start();
+}
diff --git a/lib/dvb/dvbtime.h b/lib/dvb/dvbtime.h
new file mode 100644 (file)
index 0000000..a1746b5
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef __LIB_DVB_DVBTIME_H_
+#define __LIB_DVB_DVBTIME_H_
+
+#include <lib/base/eerror.h>
+#include <lib/dvb/esection.h>
+#include <lib/dvb_si/tdt.h>
+
+class eDVBChannel;
+
+time_t parseDVBtime(__u8 t1, __u8 t2, __u8 t3, __u8 t4, __u8 t5);
+
+class TDT: public eGTable
+{
+       eDVBChannel *chan;
+       ePtr<iDVBDemux> demux;
+       eTimer m_interval_timer;
+       int createTable(int nr, const __u8 *data, unsigned int max);
+       void ready(int);
+public:
+       TDT(eDVBChannel *chan);
+       void start();
+       void startTimer(int interval);
+};
+
+class eDVBLocalTimeHandler: public Object
+{
+       friend class TDT;
+       DECLARE_REF(eDVBLocalTimeHandler)
+       std::map<iDVBChannel*, TDT*> m_active_tables;
+       std::map<eDVBChannelID,int> m_timeOffsetMap;
+       ePtr<eConnection> m_chanAddedConn;
+       ePtr<eConnection> m_chanRemovedConn;
+       ePtr<eConnection> m_chanRunningConn;
+       bool m_time_ready;
+       int m_time_difference;
+       int m_last_tp_time_difference;
+       void DVBChannelAdded(eDVBChannel*);
+       void DVBChannelRemoved(eDVBChannel*);
+       void DVBChannelRunning(iDVBChannel*);
+       void readTimeOffsetData(const char*);
+       void writeTimeOffsetData(const char*);
+       void updateTime(time_t tp_time, eDVBChannel*);
+       static eDVBLocalTimeHandler *instance;
+public:
+       PSignal0<void> m_timeUpdated;
+       eDVBLocalTimeHandler();
+       ~eDVBLocalTimeHandler();
+       bool ready() { return m_time_ready; }
+       int difference() { return m_time_difference; }
+       static eDVBLocalTimeHandler *getInstance() { return instance; }
+};
+
+#endif // __LIB_DVB_DVBTIME_H_
index a80168b..78db901 100644 (file)
@@ -57,15 +57,26 @@ RESULT eGTable::start(iDVBSectionReader *reader, const eDVBTableSpec &table)
        if (m_table.flags & eDVBTableSpec::tfHaveTID)
        {
                mask.data[0] = m_table.tid;
-               mask.mask[0] = mask.pid == 0x14 ? 0xFC : 0xFF;
+               if (m_table.flags & eDVBTableSpec::tfHaveTIDMask)
+                       mask.mask[0] = m_table.tid_mask;
+               else
+                       mask.mask[0] = 0xFF;
        }
-       
+
        if (m_table.flags & eDVBTableSpec::tfHaveTIDExt)
        {
                mask.data[1] = m_table.tidext >> 8;
                mask.data[2] = m_table.tidext;
-               mask.mask[1] = 0xFF;
-               mask.mask[2] = 0xFF;
+               if (m_table.flags & eDVBTableSpec::tfHaveTIDExtMask)
+               {
+                       mask.mask[1] = m_table.tidext_mask >> 8;
+                       mask.mask[2] = m_table.tidext_mask;
+               }
+               else
+               {
+                       mask.mask[1] = 0xFF;
+                       mask.mask[2] = 0xFF;
+               }
        }
        
        if (!(m_table.flags & eDVBTableSpec::tfAnyVersion))
index 9267d00..e48c5d9 100644 (file)
@@ -21,7 +21,7 @@ struct eDVBSectionFilterMask
 
 struct eDVBTableSpec
 {
-       int pid, tid, tidext;
+       int pid, tid, tidext, tid_mask, tidext_mask;
        int version;
        int timeout;        /* timeout in ms */
        enum
@@ -38,6 +38,8 @@ struct eDVBTableSpec
                tfHaveTIDExt=16,
                tfCheckCRC=32,
                tfHaveTimeout=64,
+               tfHaveTIDMask=128,
+               tfHaveTIDExtMask=256
        };
        int flags;
 };
index 1ed5369..5a0c5cf 100644 (file)
@@ -21,7 +21,7 @@ struct eDVBSectionFilterMask
 
 struct eDVBTableSpec
 {
-       int pid, tid, tidext;
+       int pid, tid, tidext, tid_mask, tidext_mask;
        int version;
        int timeout;        /* timeout in ms */
        enum
@@ -38,6 +38,8 @@ struct eDVBTableSpec
                tfHaveTIDExt=16,
                tfCheckCRC=32,
                tfHaveTimeout=64,
+               tfHaveTIDMask=128,
+               tfHaveTIDExtMask=256
        };
        int flags;
 };