X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/547419c9a9e81d29395e87e53bcd6174d744a4e2..aece969ad2b26fb6827f6c8d53622a67522f46b4:/lib/dvb/dvbtime.cpp diff --git a/lib/dvb/dvbtime.cpp b/lib/dvb/dvbtime.cpp index 12e52a9f..bb6b94b0 100644 --- a/lib/dvb/dvbtime.cpp +++ b/lib/dvb/dvbtime.cpp @@ -11,35 +11,63 @@ #define FP_IOCTL_SET_RTC 0x101 #define FP_IOCTL_GET_RTC 0x102 +#define TIME_UPDATE_INTERVAL (30*60*1000) + static time_t prev_time; void setRTC(time_t time) { - int fd = open("/dev/dbox/fp0", O_RDWR); - if ( fd >= 0 ) + FILE *f = fopen("/proc/stb/fp/rtc", "w"); + if (f) { - if ( ::ioctl(fd, FP_IOCTL_SET_RTC, (void*)&time ) < 0 ) - eDebug("FP_IOCTL_SET_RTC failed(%m)"); - else + if (fprintf(f, "%u", (unsigned int)time)) prev_time = time; - close(fd); + else + eDebug("write /proc/stb/fp/rtc failed (%m)"); + fclose(f); + } + else + { + 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 ) + FILE *f = fopen("/proc/stb/fp/rtc", "r"); + if (f) { - if ( ::ioctl(fd, FP_IOCTL_GET_RTC, (void*)&rtc_time ) < 0 ) - eDebug("FP_IOCTL_GET_RTC failed(%m)"); - close(fd); + // sanity check to detect corrupt atmel firmware + unsigned int tmp; + if (fscanf(f, "%u", &tmp) != 1) + eDebug("read /proc/stb/fp/rtc failed (%m)"); + else + rtc_time=tmp; + fclose(f); + } + else + { + 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; } -time_t parseDVBtime(__u8 t1, __u8 t2, __u8 t3, __u8 t4, __u8 t5) +time_t parseDVBtime(__u8 t1, __u8 t2, __u8 t3, __u8 t4, __u8 t5, __u16 *hash) { tm t; t.tm_sec=fromBCD(t5); @@ -59,14 +87,19 @@ time_t parseDVBtime(__u8 t1, __u8 t2, __u8 t3, __u8 t4, __u8 t5) t.tm_isdst = 0; t.tm_gmtoff = 0; + if (hash) { + *hash = t.tm_hour * 60 + t.tm_min; + *hash |= t.tm_mday << 11; + } + return timegm(&t); } TDT::TDT(eDVBChannel *chan, int update_count) - :chan(chan), update_count(update_count) + :chan(chan), m_interval_timer(eTimer::create()), update_count(update_count) { CONNECT(tableReady, TDT::ready); - CONNECT(m_interval_timer.timeout, TDT::start); + CONNECT(m_interval_timer->timeout, TDT::start); if (chan) chan->getDemux(demux, 0); } @@ -76,7 +109,7 @@ void TDT::ready(int error) eDVBLocalTimeHandler::getInstance()->updateTime(error, chan, ++update_count); } -int TDT::createTable(int nr, const __u8 *data, unsigned int max) +int TDT::createTable(unsigned int nr, const __u8 *data, unsigned int max) { if ( data && data[0] == 0x70 || data[0] == 0x73 ) { @@ -84,7 +117,8 @@ int TDT::createTable(int nr, const __u8 *data, unsigned int max) if ( length >= 5 ) { time_t tptime = parseDVBtime(data[3], data[4], data[5], data[6], data[7]); - eDVBLocalTimeHandler::getInstance()->updateTime(tptime, chan, update_count); + if (tptime && tptime != -1) + eDVBLocalTimeHandler::getInstance()->updateTime(tptime, chan, update_count); error=0; return 1; } @@ -112,14 +146,14 @@ void TDT::start() void TDT::startTimer( int interval ) { - m_interval_timer.start(interval, true); + m_interval_timer->start(interval, true); } eDVBLocalTimeHandler *eDVBLocalTimeHandler::instance; DEFINE_REF(eDVBLocalTimeHandler); eDVBLocalTimeHandler::eDVBLocalTimeHandler() - :m_time_ready(false), m_time_difference(0) + :m_use_dvb_time(false), m_updateNonTunedTimer(eTimer::create(eApp)), m_time_ready(false) { if ( !instance ) instance=this; @@ -128,14 +162,29 @@ eDVBLocalTimeHandler::eDVBLocalTimeHandler() if (!res_mgr) eDebug("[eDVBLocalTimerHandler] no resource manager !!!!!!!"); else + { res_mgr->connectChannelAdded(slot(*this,&eDVBLocalTimeHandler::DVBChannelAdded), m_chanAddedConn); + time_t now = time(0); + if ( now < 1072224000 ) // 01.01.2004 + eDebug("RTC not ready... wait for transponder time"); + else // inform all who's waiting for valid system time.. + { + eDebug("Use valid Linux Time :) (RTC?)"); + m_time_ready = true; + /*emit*/ m_timeUpdated(); + } + } + CONNECT(m_updateNonTunedTimer->timeout, eDVBLocalTimeHandler::updateNonTuned); } eDVBLocalTimeHandler::~eDVBLocalTimeHandler() { instance=0; - for (std::map::iterator it=m_knownChannels.begin(); it != m_knownChannels.end(); ++it) - delete it->second.tdt; + if (ready()) + { + eDebug("set RTC to previous valid time"); + setRTC(::time(0)); + } } void eDVBLocalTimeHandler::readTimeOffsetData( const char* filename ) @@ -173,8 +222,42 @@ void eDVBLocalTimeHandler::writeTimeOffsetData( const char* filename ) } } +void eDVBLocalTimeHandler::setUseDVBTime(bool b) +{ + if (m_use_dvb_time != b) { + if (m_use_dvb_time) { + eDebug("[eDVBLocalTimeHandler] disable sync local time with transponder time!"); + std::map::iterator it = + m_knownChannels.begin(); + for (; it != m_knownChannels.end(); ++it) { + if (it->second.m_prevChannelState == iDVBChannel::state_ok) + it->second.tdt = 0; + } + } + else { + eDebug("[eDVBLocalTimeHandler] enable sync local time with transponder time!"); + std::map::iterator it = + m_knownChannels.begin(); + for (; it != m_knownChannels.end(); ++it) { + if (it->second.m_prevChannelState == iDVBChannel::state_ok) { + it->second.tdt = new TDT(it->second.channel); + it->second.tdt->start(); + } + } + } + m_use_dvb_time = b; + } +} + +void eDVBLocalTimeHandler::updateNonTuned() +{ + updateTime(-1, 0, 0); + m_updateNonTunedTimer->start(TIME_UPDATE_INTERVAL, true); +} + void eDVBLocalTimeHandler::updateTime( time_t tp_time, eDVBChannel *chan, int update_count ) { + int time_difference; bool restart_tdt = false; if (!tp_time) restart_tdt = true; @@ -189,31 +272,29 @@ void eDVBLocalTimeHandler::updateTime( time_t tp_time, eDVBChannel *chan, int up time_t rtc_time = getRTC(); if ( rtc_time ) // RTC Ready? { - tm now = *localtime(&rtc_time); + tm now; + localtime_r(&rtc_time, &now); 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); + localtime_r(&linuxTime, &now); 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 ) + time_difference = rtc_time - linuxTime; + eDebug("[eDVBLocalTimerHandler] RTC to Receiver time difference is %ld seconds", linuxTime - rtc_time ); + if ( time_difference ) { eDebug("[eDVBLocalTimerHandler] set Linux Time to RTC Time"); timeval tnow; gettimeofday(&tnow,0); tnow.tv_sec=rtc_time; settimeofday(&tnow,0); - eMainloop::addTimeOffset(m_time_difference); - m_time_difference=0; } - else if ( !m_time_difference ) + else if ( !time_difference ) eDebug("[eDVBLocalTimerHandler] no change needed"); else eDebug("[eDVBLocalTimerHandler] set to RTC time"); @@ -230,11 +311,8 @@ void eDVBLocalTimeHandler::updateTime( time_t tp_time, eDVBChannel *chan, int up // 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 enigma_diff = tp_time-linuxTime; int new_diff=0; @@ -255,20 +333,19 @@ void eDVBLocalTimeHandler::updateTime( time_t tp_time, eDVBChannel *chan, int up { eDebug("[eDVBLocalTimerHandler] we have correction %d", it->second); time_t CorrectedTpTime = tp_time+it->second; - int ddiff = CorrectedTpTime-nowTime; + int ddiff = CorrectedTpTime-linuxTime; 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() ) + else if ( 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 ); + new_diff = rtc-linuxTime; // set enigma time to rtc + eDebug("[eDVBLocalTimerHandler] update stored correction to %ld (calced against RTC time)", rtc-tp_time ); } else if ( abs(ddiff) <= 120 ) { @@ -303,7 +380,7 @@ void eDVBLocalTimeHandler::updateTime( time_t tp_time, eDVBChannel *chan, int up m_time_ready=true; } - time_t t = nowTime+new_diff; + time_t t = linuxTime+new_diff; m_last_tp_time_difference=tp_time-t; if (!new_diff && @@ -313,16 +390,6 @@ void eDVBLocalTimeHandler::updateTime( time_t tp_time, eDVBChannel *chan, int up 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 !! if ( !update_count ) { // set rtc to calced transponder time when the first tdt is received on this @@ -330,18 +397,36 @@ void eDVBLocalTimeHandler::updateTime( time_t tp_time, eDVBChannel *chan, int up setRTC(t); eDebug("[eDVBLocalTimerHandler] update RTC"); } + else if (getRTC()) + { + if (abs(getRTC() - t) > 60) + { + eDebug("[eDVBLocalTimerHandler] difference between new linux time and RTC time is > 60 sec... transponder time looks not ok... use rtc time"); + t = getRTC(); + } + else + eDebug("[eDVBLocalTimerHandler] difference between linux time and RTC time is < 60 sec... so the transponder time looks ok"); + } else - eDebug("[eDVBLocalTimerHandler] don't update RTC"); + eDebug("[eDVBLocalTimerHandler] no RTC available :("); + + tm now; + localtime_r(&t, &now); + eDebug("[eDVBLocalTimerHandler] time update to %02d:%02d:%02d", + now.tm_hour, + now.tm_min, + now.tm_sec); - if ( abs(m_time_difference) > 59 ) + time_difference = t - linuxTime; // calc our new linux_time -> enigma_time correction + eDebug("[eDVBLocalTimerHandler] m_time_difference is %d", time_difference ); + + if ( time_difference ) { eDebug("[eDVBLocalTimerHandler] set Linux Time"); timeval tnow; gettimeofday(&tnow,0); tnow.tv_sec=t; settimeofday(&tnow,0); - eMainloop::addTimeOffset(m_time_difference); - m_time_difference=0; } /*emit*/ m_timeUpdated(); @@ -353,10 +438,10 @@ void eDVBLocalTimeHandler::updateTime( time_t tp_time, eDVBChannel *chan, int up m_knownChannels.find(chan); if ( it != m_knownChannels.end() ) { - TDT *prev_tdt = it->second.tdt; - it->second.tdt = new TDT(chan, prev_tdt->getUpdateCount()); - it->second.tdt->startTimer(60*60*1000); // restart TDT for this transponder in 60min - delete prev_tdt; + int updateCount = it->second.tdt->getUpdateCount(); + it->second.tdt = 0; + it->second.tdt = new TDT(chan, updateCount); + it->second.tdt->startTimer(TIME_UPDATE_INTERVAL); // restart TDT for this transponder in 30min } } } @@ -370,6 +455,7 @@ void eDVBLocalTimeHandler::DVBChannelAdded(eDVBChannel *chan) m_knownChannels.insert( std::pair(chan, channel_data()) ); tmp.first->second.tdt = NULL; tmp.first->second.channel = chan; + tmp.first->second.m_prevChannelState = -1; chan->connectStateChange(slot(*this, &eDVBLocalTimeHandler::DVBChannelStateChanged), tmp.first->second.m_stateChangedConn); } } @@ -382,18 +468,28 @@ void eDVBLocalTimeHandler::DVBChannelStateChanged(iDVBChannel *chan) { int state=0; chan->getState(state); - switch (state) + if ( state != it->second.m_prevChannelState ) { - case iDVBChannel::state_ok: - eDebug("[eDVBLocalTimerHandler] channel %p running", chan); - it->second.tdt = new TDT(it->second.channel); - it->second.tdt->start(); - break; - case iDVBChannel::state_release: - eDebug("[eDVBLocalTimerHandler] remove channel %p", chan); - delete it->second.tdt; - m_knownChannels.erase(it); - break; + switch (state) + { + case iDVBChannel::state_ok: + eDebug("[eDVBLocalTimerHandler] channel %p running", chan); + m_updateNonTunedTimer->stop(); + if (m_use_dvb_time) { + it->second.tdt = new TDT(it->second.channel); + it->second.tdt->start(); + } + break; + case iDVBChannel::state_release: + eDebug("[eDVBLocalTimerHandler] remove channel %p", chan); + m_knownChannels.erase(it); + if (m_knownChannels.empty()) + m_updateNonTunedTimer->start(TIME_UPDATE_INTERVAL, true); + break; + default: // ignore all other events + return; + } + it->second.m_prevChannelState = state; } } }