1 #include <lib/dvb/dvbtime.h>
2 #include <lib/dvb/dvb.h>
10 // defines for DM7000 / DM7020
11 #define FP_IOCTL_SET_RTC 0x101
12 #define FP_IOCTL_GET_RTC 0x102
14 #define TIME_UPDATE_INTERVAL (30*60*1000)
16 static time_t prev_time;
18 void setRTC(time_t time)
20 FILE *f = fopen("/proc/stb/fp/rtc", "w");
23 if (fprintf(f, "%u", (unsigned int)time))
26 eDebug("write /proc/stb/fp/rtc failed (%m)");
31 int fd = open("/dev/dbox/fp0", O_RDWR);
34 if ( ::ioctl(fd, FP_IOCTL_SET_RTC, (void*)&time ) < 0 )
35 eDebug("FP_IOCTL_SET_RTC failed(%m)");
46 FILE *f = fopen("/proc/stb/fp/rtc", "r");
49 // sanity check to detect corrupt atmel firmware
51 if (fscanf(f, "%u", &tmp) != 1)
52 eDebug("read /proc/stb/fp/rtc failed (%m)");
59 int fd = open("/dev/dbox/fp0", O_RDWR);
62 if ( ::ioctl(fd, FP_IOCTL_GET_RTC, (void*)&rtc_time ) < 0 )
63 eDebug("FP_IOCTL_GET_RTC failed(%m)");
67 return rtc_time != prev_time ? rtc_time : 0;
70 time_t parseDVBtime(__u8 t1, __u8 t2, __u8 t3, __u8 t4, __u8 t5, __u16 *hash)
75 t.tm_hour=fromBCD(t3);
79 t.tm_year = (int) ((mjd - 15078.2) / 365.25);
80 t.tm_mon = (int) ((mjd - 14956.1 - (int)(t.tm_year * 365.25)) / 30.6001);
81 t.tm_mday = (int) (mjd - 14956 - (int)(t.tm_year * 365.25) - (int)(t.tm_mon * 30.6001));
82 k = (t.tm_mon == 14 || t.tm_mon == 15) ? 1 : 0;
83 t.tm_year = t.tm_year + k;
84 t.tm_mon = t.tm_mon - 1 - k * 12;
91 *hash = t.tm_hour * 60 + t.tm_min;
92 *hash |= t.tm_mday << 11;
98 TDT::TDT(eDVBChannel *chan, int update_count)
99 :chan(chan), m_interval_timer(eTimer::create()), update_count(update_count)
101 CONNECT(tableReady, TDT::ready);
102 CONNECT(m_interval_timer->timeout, TDT::start);
104 chan->getDemux(demux, 0);
107 void TDT::ready(int error)
109 eDVBLocalTimeHandler::getInstance()->updateTime(error, chan, ++update_count);
112 int TDT::createTable(unsigned int nr, const __u8 *data, unsigned int max)
114 if ( data && (data[0] == 0x70 || data[0] == 0x73 ))
116 int length = ((data[1] & 0x0F) << 8) | data[2];
119 time_t tptime = parseDVBtime(data[3], data[4], data[5], data[6], data[7]);
120 if (tptime && tptime != -1)
121 eDVBLocalTimeHandler::getInstance()->updateTime(tptime, chan, update_count);
134 spec.pid = TimeAndDateSection::PID;
135 spec.tid = TimeAndDateSection::TID;
136 spec.tid_mask = 0xFC;
137 spec.timeout = TimeAndDateSection::TIMEOUT;
138 spec.flags= eDVBTableSpec::tfAnyVersion |
139 eDVBTableSpec::tfHaveTID |
140 eDVBTableSpec::tfHaveTIDMask |
141 eDVBTableSpec::tfHaveTimeout;
143 eGTable::start( demux, spec );
147 void TDT::startTimer( int interval )
149 m_interval_timer->start(interval, true);
152 eDVBLocalTimeHandler *eDVBLocalTimeHandler::instance;
153 DEFINE_REF(eDVBLocalTimeHandler);
155 eDVBLocalTimeHandler::eDVBLocalTimeHandler()
156 :m_use_dvb_time(false), m_updateNonTunedTimer(eTimer::create(eApp)), m_time_ready(false)
160 ePtr<eDVBResourceManager> res_mgr;
161 eDVBResourceManager::getInstance(res_mgr);
163 eDebug("[eDVBLocalTimerHandler] no resource manager !!!!!!!");
166 res_mgr->connectChannelAdded(slot(*this,&eDVBLocalTimeHandler::DVBChannelAdded), m_chanAddedConn);
167 time_t now = time(0);
168 if ( now < 1072224000 ) // 01.01.2004
169 eDebug("RTC not ready... wait for transponder time");
170 else // inform all who's waiting for valid system time..
172 eDebug("Use valid Linux Time :) (RTC?)");
174 /*emit*/ m_timeUpdated();
177 CONNECT(m_updateNonTunedTimer->timeout, eDVBLocalTimeHandler::updateNonTuned);
180 eDVBLocalTimeHandler::~eDVBLocalTimeHandler()
185 eDebug("set RTC to previous valid time");
190 void eDVBLocalTimeHandler::readTimeOffsetData( const char* filename )
192 m_timeOffsetMap.clear();
193 FILE *f=fopen(filename, "r");
200 if (!fgets( line, 256, f ))
202 if (strstr(line, "Transponder UTC Time Offsets\n"))
204 int dvbnamespace,tsid,onid,offs;
205 if ( sscanf( line, "%08x,%04x,%04x:%d\n",&dvbnamespace,&tsid,&onid,&offs ) == 4 )
206 m_timeOffsetMap[eDVBChannelID(dvbnamespace,tsid,onid)]=offs;
211 void eDVBLocalTimeHandler::writeTimeOffsetData( const char* filename )
213 FILE *f=fopen(filename, "w+");
216 fprintf(f, "Transponder UTC Time Offsets\n");
217 for ( std::map<eDVBChannelID,int>::iterator it ( m_timeOffsetMap.begin() ); it != m_timeOffsetMap.end(); ++it )
218 fprintf(f, "%08x,%04x,%04x:%d\n",
219 it->first.dvbnamespace.get(),
220 it->first.transport_stream_id.get(), it->first.original_network_id.get(), it->second );
225 void eDVBLocalTimeHandler::setUseDVBTime(bool b)
227 if (m_use_dvb_time != b) {
228 if (m_use_dvb_time) {
229 eDebug("[eDVBLocalTimeHandler] disable sync local time with transponder time!");
230 std::map<iDVBChannel*, channel_data>::iterator it =
231 m_knownChannels.begin();
232 for (; it != m_knownChannels.end(); ++it) {
233 if (it->second.m_prevChannelState == iDVBChannel::state_ok)
238 eDebug("[eDVBLocalTimeHandler] enable sync local time with transponder time!");
239 std::map<iDVBChannel*, channel_data>::iterator it =
240 m_knownChannels.begin();
241 for (; it != m_knownChannels.end(); ++it) {
242 if (it->second.m_prevChannelState == iDVBChannel::state_ok) {
243 it->second.tdt = new TDT(it->second.channel);
244 it->second.tdt->start();
252 void eDVBLocalTimeHandler::updateNonTuned()
254 updateTime(-1, 0, 0);
255 m_updateNonTunedTimer->start(TIME_UPDATE_INTERVAL, true);
258 void eDVBLocalTimeHandler::updateTime( time_t tp_time, eDVBChannel *chan, int update_count )
261 bool restart_tdt = false;
264 else if (tp_time == -1)
267 /*if ( eSystemInfo::getInstance()->getHwType() == eSystemInfo::DM7020 ||
268 ( eSystemInfo::getInstance()->getHwType() == eSystemInfo::DM7000
269 && eSystemInfo::getInstance()->hasStandbyWakeupTimer() ) ) TODO !!!!!!! */
271 eDebug("[eDVBLocalTimerHandler] no transponder tuned... or no TDT/TOT avail .. try to use RTC :)");
272 time_t rtc_time = getRTC();
273 if ( rtc_time ) // RTC Ready?
276 localtime_r(&rtc_time, &now);
277 eDebug("[eDVBLocalTimerHandler] RTC time is %02d:%02d:%02d",
281 time_t linuxTime=time(0);
282 localtime_r(&linuxTime, &now);
283 eDebug("[eDVBLocalTimerHandler] Receiver time is %02d:%02d:%02d",
287 time_difference = rtc_time - linuxTime;
288 eDebug("[eDVBLocalTimerHandler] RTC to Receiver time difference is %ld seconds", linuxTime - rtc_time );
289 if ( time_difference )
291 eDebug("[eDVBLocalTimerHandler] set Linux Time to RTC Time");
293 gettimeofday(&tnow,0);
294 tnow.tv_sec=rtc_time;
295 settimeofday(&tnow,0);
297 else if ( !time_difference )
298 eDebug("[eDVBLocalTimerHandler] no change needed");
300 eDebug("[eDVBLocalTimerHandler] set to RTC time");
301 /*emit*/ m_timeUpdated();
304 eDebug("[eDVBLocalTimerHandler] shit RTC not ready :(");
309 std::map< eDVBChannelID, int >::iterator it( m_timeOffsetMap.find( chan->getChannelID() ) );
311 // current linux time
312 time_t linuxTime = time(0);
314 // difference between current enigma time and transponder time
315 int enigma_diff = tp_time-linuxTime;
319 bool updated = m_time_ready;
321 if ( m_time_ready ) // ref time ready?
323 // difference between reference time (current enigma time)
324 // and the transponder time
325 eDebug("[eDVBLocalTimerHandler] diff is %d", enigma_diff);
326 if ( abs(enigma_diff) < 120 )
328 eDebug("[eDVBLocalTimerHandler] diff < 120 .. use Transponder Time");
329 m_timeOffsetMap[chan->getChannelID()] = 0;
330 new_diff = enigma_diff;
332 else if ( it != m_timeOffsetMap.end() ) // correction saved?
334 eDebug("[eDVBLocalTimerHandler] we have correction %d", it->second);
335 time_t CorrectedTpTime = tp_time+it->second;
336 int ddiff = CorrectedTpTime-linuxTime;
337 eDebug("[eDVBLocalTimerHandler] diff after add correction is %d", ddiff);
338 if ( abs(it->second) < 300 ) // stored correction < 5 min
340 eDebug("[eDVBLocalTimerHandler] use stored correction(<5 min)");
346 m_timeOffsetMap[chan->getChannelID()] = rtc-tp_time;
347 new_diff = rtc-linuxTime; // set enigma time to rtc
348 eDebug("[eDVBLocalTimerHandler] update stored correction to %ld (calced against RTC time)", rtc-tp_time );
350 else if ( abs(ddiff) <= 120 )
352 // with stored correction calced time difference is lower 2 min
353 // this don't help when a transponder have a clock running to slow or to fast
354 // then its better to have a DM7020 with always running RTC
355 eDebug("[eDVBLocalTimerHandler] use stored correction(corr < 2 min)");
358 else // big change in calced correction.. hold current time and update correction
360 eDebug("[eDVBLocalTimerHandler] update stored correction to %d", -enigma_diff);
361 m_timeOffsetMap[chan->getChannelID()] = -enigma_diff;
366 eDebug("[eDVBLocalTimerHandler] no correction found... store calced correction(%d)",-enigma_diff);
367 m_timeOffsetMap[chan->getChannelID()] = -enigma_diff;
370 else // no time setted yet
372 if ( it != m_timeOffsetMap.end() )
374 enigma_diff += it->second;
375 eDebug("[eDVBLocalTimerHandler] we have correction (%d)... use", it->second );
378 eDebug("[eDVBLocalTimerHandler] dont have correction.. set Transponder Diff");
379 new_diff=enigma_diff;
383 time_t t = linuxTime+new_diff;
384 m_last_tp_time_difference=tp_time-t;
387 updated) // overrride this check on first received TDT
389 eDebug("[eDVBLocalTimerHandler] not changed");
395 // set rtc to calced transponder time when the first tdt is received on this
398 eDebug("[eDVBLocalTimerHandler] update RTC");
402 if (abs(getRTC() - t) > 60)
404 eDebug("[eDVBLocalTimerHandler] difference between new linux time and RTC time is > 60 sec... transponder time looks not ok... use rtc time");
408 eDebug("[eDVBLocalTimerHandler] difference between linux time and RTC time is < 60 sec... so the transponder time looks ok");
411 eDebug("[eDVBLocalTimerHandler] no RTC available :(");
414 localtime_r(&t, &now);
415 eDebug("[eDVBLocalTimerHandler] time update to %02d:%02d:%02d",
420 time_difference = t - linuxTime; // calc our new linux_time -> enigma_time correction
421 eDebug("[eDVBLocalTimerHandler] m_time_difference is %d", time_difference );
423 if ( time_difference )
425 eDebug("[eDVBLocalTimerHandler] set Linux Time");
427 gettimeofday(&tnow,0);
429 settimeofday(&tnow,0);
432 /*emit*/ m_timeUpdated();
437 std::map<iDVBChannel*, channel_data>::iterator it =
438 m_knownChannels.find(chan);
439 if ( it != m_knownChannels.end() )
441 int updateCount = it->second.tdt->getUpdateCount();
443 it->second.tdt = new TDT(chan, updateCount);
444 it->second.tdt->startTimer(TIME_UPDATE_INTERVAL); // restart TDT for this transponder in 30min
449 void eDVBLocalTimeHandler::DVBChannelAdded(eDVBChannel *chan)
453 // eDebug("[eDVBLocalTimerHandler] add channel %p", chan);
454 std::pair<std::map<iDVBChannel*, channel_data>::iterator, bool> tmp =
455 m_knownChannels.insert( std::pair<iDVBChannel*, channel_data>(chan, channel_data()) );
456 tmp.first->second.tdt = NULL;
457 tmp.first->second.channel = chan;
458 tmp.first->second.m_prevChannelState = -1;
459 chan->connectStateChange(slot(*this, &eDVBLocalTimeHandler::DVBChannelStateChanged), tmp.first->second.m_stateChangedConn);
463 void eDVBLocalTimeHandler::DVBChannelStateChanged(iDVBChannel *chan)
465 std::map<iDVBChannel*, channel_data>::iterator it =
466 m_knownChannels.find(chan);
467 if ( it != m_knownChannels.end() )
470 chan->getState(state);
471 if ( state != it->second.m_prevChannelState )
475 case iDVBChannel::state_ok:
476 eDebug("[eDVBLocalTimerHandler] channel %p running", chan);
477 m_updateNonTunedTimer->stop();
478 if (m_use_dvb_time) {
479 it->second.tdt = new TDT(it->second.channel);
480 it->second.tdt->start();
483 case iDVBChannel::state_release:
484 eDebug("[eDVBLocalTimerHandler] remove channel %p", chan);
485 m_knownChannels.erase(it);
486 if (m_knownChannels.empty())
487 m_updateNonTunedTimer->start(TIME_UPDATE_INTERVAL, true);
489 default: // ignore all other events
492 it->second.m_prevChannelState = state;