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 static time_t prev_time;
16 void setRTC(time_t time)
18 int fd = open("/dev/dbox/fp0", O_RDWR);
21 if ( ::ioctl(fd, FP_IOCTL_SET_RTC, (void*)&time ) < 0 )
22 eDebug("FP_IOCTL_SET_RTC failed(%m)");
32 int fd = open("/dev/dbox/fp0", O_RDWR);
35 if ( ::ioctl(fd, FP_IOCTL_GET_RTC, (void*)&rtc_time ) < 0 )
36 eDebug("FP_IOCTL_GET_RTC failed(%m)");
39 return rtc_time != prev_time ? rtc_time : 0;
42 time_t parseDVBtime(__u8 t1, __u8 t2, __u8 t3, __u8 t4, __u8 t5)
47 t.tm_hour=fromBCD(t3);
51 t.tm_year = (int) ((mjd - 15078.2) / 365.25);
52 t.tm_mon = (int) ((mjd - 14956.1 - (int)(t.tm_year * 365.25)) / 30.6001);
53 t.tm_mday = (int) (mjd - 14956 - (int)(t.tm_year * 365.25) - (int)(t.tm_mon * 30.6001));
54 k = (t.tm_mon == 14 || t.tm_mon == 15) ? 1 : 0;
55 t.tm_year = t.tm_year + k;
56 t.tm_mon = t.tm_mon - 1 - k * 12;
65 TDT::TDT(eDVBChannel *chan, int update_count)
66 :chan(chan), update_count(update_count)
68 CONNECT(tableReady, TDT::ready);
69 CONNECT(m_interval_timer.timeout, TDT::start);
71 chan->getDemux(demux, 0);
74 void TDT::ready(int error)
76 eDVBLocalTimeHandler::getInstance()->updateTime(error, chan, ++update_count);
79 int TDT::createTable(unsigned int nr, const __u8 *data, unsigned int max)
81 if ( data && data[0] == 0x70 || data[0] == 0x73 )
83 int length = ((data[1] & 0x0F) << 8) | data[2];
86 time_t tptime = parseDVBtime(data[3], data[4], data[5], data[6], data[7]);
87 if (tptime && tptime != -1)
88 eDVBLocalTimeHandler::getInstance()->updateTime(tptime, chan, update_count);
101 spec.pid = TimeAndDateSection::PID;
102 spec.tid = TimeAndDateSection::TID;
103 spec.tid_mask = 0xFC;
104 spec.timeout = TimeAndDateSection::TIMEOUT;
105 spec.flags= eDVBTableSpec::tfAnyVersion |
106 eDVBTableSpec::tfHaveTID |
107 eDVBTableSpec::tfHaveTIDMask |
108 eDVBTableSpec::tfHaveTimeout;
110 eGTable::start( demux, spec );
114 void TDT::startTimer( int interval )
116 m_interval_timer.start(interval, true);
119 eDVBLocalTimeHandler *eDVBLocalTimeHandler::instance;
120 DEFINE_REF(eDVBLocalTimeHandler);
122 eDVBLocalTimeHandler::eDVBLocalTimeHandler()
123 :m_time_ready(false), m_time_difference(0)
127 ePtr<eDVBResourceManager> res_mgr;
128 eDVBResourceManager::getInstance(res_mgr);
130 eDebug("[eDVBLocalTimerHandler] no resource manager !!!!!!!");
132 res_mgr->connectChannelAdded(slot(*this,&eDVBLocalTimeHandler::DVBChannelAdded), m_chanAddedConn);
135 eDVBLocalTimeHandler::~eDVBLocalTimeHandler()
138 for (std::map<iDVBChannel*, channel_data>::iterator it=m_knownChannels.begin(); it != m_knownChannels.end(); ++it)
139 delete it->second.tdt;
142 void eDVBLocalTimeHandler::readTimeOffsetData( const char* filename )
144 m_timeOffsetMap.clear();
145 FILE *f=fopen(filename, "r");
152 if (!fgets( line, 256, f ))
154 if (strstr(line, "Transponder UTC Time Offsets\n"))
156 int dvbnamespace,tsid,onid,offs;
157 if ( sscanf( line, "%08x,%04x,%04x:%d\n",&dvbnamespace,&tsid,&onid,&offs ) == 4 )
158 m_timeOffsetMap[eDVBChannelID(dvbnamespace,tsid,onid)]=offs;
163 void eDVBLocalTimeHandler::writeTimeOffsetData( const char* filename )
165 FILE *f=fopen(filename, "w+");
168 fprintf(f, "Transponder UTC Time Offsets\n");
169 for ( std::map<eDVBChannelID,int>::iterator it ( m_timeOffsetMap.begin() ); it != m_timeOffsetMap.end(); ++it )
170 fprintf(f, "%08x,%04x,%04x:%d\n",
171 it->first.dvbnamespace.get(),
172 it->first.transport_stream_id.get(), it->first.original_network_id.get(), it->second );
177 void eDVBLocalTimeHandler::updateTime( time_t tp_time, eDVBChannel *chan, int update_count )
179 bool restart_tdt = false;
182 else if (tp_time == -1)
185 /*if ( eSystemInfo::getInstance()->getHwType() == eSystemInfo::DM7020 ||
186 ( eSystemInfo::getInstance()->getHwType() == eSystemInfo::DM7000
187 && eSystemInfo::getInstance()->hasStandbyWakeupTimer() ) ) TODO !!!!!!! */
189 eDebug("[eDVBLocalTimerHandler] no transponder tuned... or no TDT/TOT avail .. try to use RTC :)");
190 time_t rtc_time = getRTC();
191 if ( rtc_time ) // RTC Ready?
194 localtime_r(&rtc_time, &now);
195 eDebug("[eDVBLocalTimerHandler] RTC time is %02d:%02d:%02d",
199 time_t linuxTime=time(0);
200 time_t nowTime=linuxTime+m_time_difference;
201 localtime_r(&nowTime, &now);
202 eDebug("[eDVBLocalTimerHandler] Receiver time is %02d:%02d:%02d",
206 m_time_difference = rtc_time - linuxTime;
207 eDebug("[eDVBLocalTimerHandler] RTC to Receiver time difference is %ld seconds", nowTime - rtc_time );
208 if ( abs(m_time_difference) > 59 )
210 eDebug("[eDVBLocalTimerHandler] set Linux Time to RTC Time");
212 gettimeofday(&tnow,0);
213 tnow.tv_sec=rtc_time;
214 settimeofday(&tnow,0);
215 eMainloop::addTimeOffset(m_time_difference);
218 else if ( !m_time_difference )
219 eDebug("[eDVBLocalTimerHandler] no change needed");
221 eDebug("[eDVBLocalTimerHandler] set to RTC time");
222 /*emit*/ m_timeUpdated();
225 eDebug("[eDVBLocalTimerHandler] shit RTC not ready :(");
230 std::map< eDVBChannelID, int >::iterator it( m_timeOffsetMap.find( chan->getChannelID() ) );
232 // current linux time
233 time_t linuxTime = time(0);
235 // current enigma time
236 time_t nowTime=linuxTime+m_time_difference;
238 // difference between current enigma time and transponder time
239 int enigma_diff = tp_time-nowTime;
243 bool updated = m_time_ready;
245 if ( m_time_ready ) // ref time ready?
247 // difference between reference time (current enigma time)
248 // and the transponder time
249 eDebug("[eDVBLocalTimerHandler] diff is %d", enigma_diff);
250 if ( abs(enigma_diff) < 120 )
252 eDebug("[eDVBLocalTimerHandler] diff < 120 .. use Transponder Time");
253 m_timeOffsetMap[chan->getChannelID()] = 0;
254 new_diff = enigma_diff;
256 else if ( it != m_timeOffsetMap.end() ) // correction saved?
258 eDebug("[eDVBLocalTimerHandler] we have correction %d", it->second);
259 time_t CorrectedTpTime = tp_time+it->second;
260 int ddiff = CorrectedTpTime-nowTime;
261 eDebug("[eDVBLocalTimerHandler] diff after add correction is %d", ddiff);
262 if ( abs(it->second) < 300 ) // stored correction < 5 min
264 eDebug("[eDVBLocalTimerHandler] use stored correction(<5 min)");
267 else if ( /*eSystemInfo::getInstance()->getHwType() == eSystemInfo::DM7020 && TODO !!!*/
271 m_timeOffsetMap[chan->getChannelID()] = rtc-tp_time;
272 new_diff = rtc-nowTime; // set enigma time to rtc
273 eDebug("[eDVBLocalTimerHandler] update stored correction to %ld (calced against RTC time)", rtc-tp_time );
275 else if ( abs(ddiff) <= 120 )
277 // with stored correction calced time difference is lower 2 min
278 // this don't help when a transponder have a clock running to slow or to fast
279 // then its better to have a DM7020 with always running RTC
280 eDebug("[eDVBLocalTimerHandler] use stored correction(corr < 2 min)");
283 else // big change in calced correction.. hold current time and update correction
285 eDebug("[eDVBLocalTimerHandler] update stored correction to %d", -enigma_diff);
286 m_timeOffsetMap[chan->getChannelID()] = -enigma_diff;
291 eDebug("[eDVBLocalTimerHandler] no correction found... store calced correction(%d)",-enigma_diff);
292 m_timeOffsetMap[chan->getChannelID()] = -enigma_diff;
295 else // no time setted yet
297 if ( it != m_timeOffsetMap.end() )
299 enigma_diff += it->second;
300 eDebug("[eDVBLocalTimerHandler] we have correction (%d)... use", it->second );
303 eDebug("[eDVBLocalTimerHandler] dont have correction.. set Transponder Diff");
304 new_diff=enigma_diff;
308 time_t t = nowTime+new_diff;
309 m_last_tp_time_difference=tp_time-t;
312 updated) // overrride this check on first received TDT
314 eDebug("[eDVBLocalTimerHandler] not changed");
319 localtime_r(&t, &now);
320 eDebug("[eDVBLocalTimerHandler] time update to %02d:%02d:%02d",
325 m_time_difference = t - linuxTime; // calc our new linux_time -> enigma_time correction
326 eDebug("[eDVBLocalTimerHandler] m_time_difference is %d", m_time_difference );
328 // if ( eSystemInfo::getInstance()->getHwType() == eSystemInfo::DM7020 ) TODO !!
331 // set rtc to calced transponder time when the first tdt is received on this
334 eDebug("[eDVBLocalTimerHandler] update RTC");
337 eDebug("[eDVBLocalTimerHandler] don't update RTC");
339 if ( abs(m_time_difference) > 59 )
341 eDebug("[eDVBLocalTimerHandler] set Linux Time");
343 gettimeofday(&tnow,0);
345 settimeofday(&tnow,0);
346 eMainloop::addTimeOffset(m_time_difference);
350 /*emit*/ m_timeUpdated();
355 std::map<iDVBChannel*, channel_data>::iterator it =
356 m_knownChannels.find(chan);
357 if ( it != m_knownChannels.end() )
359 TDT *prev_tdt = it->second.tdt;
360 it->second.tdt = new TDT(chan, prev_tdt->getUpdateCount());
361 it->second.tdt->startTimer(60*60*1000); // restart TDT for this transponder in 60min
367 void eDVBLocalTimeHandler::DVBChannelAdded(eDVBChannel *chan)
371 // eDebug("[eDVBLocalTimerHandler] add channel %p", chan);
372 std::pair<std::map<iDVBChannel*, channel_data>::iterator, bool> tmp =
373 m_knownChannels.insert( std::pair<iDVBChannel*, channel_data>(chan, channel_data()) );
374 tmp.first->second.tdt = NULL;
375 tmp.first->second.channel = chan;
376 tmp.first->second.m_prevChannelState = -1;
377 chan->connectStateChange(slot(*this, &eDVBLocalTimeHandler::DVBChannelStateChanged), tmp.first->second.m_stateChangedConn);
381 void eDVBLocalTimeHandler::DVBChannelStateChanged(iDVBChannel *chan)
383 std::map<iDVBChannel*, channel_data>::iterator it =
384 m_knownChannels.find(chan);
385 if ( it != m_knownChannels.end() )
388 chan->getState(state);
389 if ( state != it->second.m_prevChannelState )
393 case iDVBChannel::state_ok:
394 eDebug("[eDVBLocalTimerHandler] channel %p running", chan);
395 it->second.tdt = new TDT(it->second.channel);
396 it->second.tdt->start();
398 case iDVBChannel::state_release:
399 eDebug("[eDVBLocalTimerHandler] remove channel %p", chan);
400 delete it->second.tdt;
401 m_knownChannels.erase(it);
403 default: // ignore all other events
406 it->second.m_prevChannelState = state;