1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
|
#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;
}
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, int update_count)
:chan(chan), update_count(update_count)
{
CONNECT(tableReady, TDT::ready);
CONNECT(m_interval_timer.timeout, TDT::start);
if (chan)
chan->getDemux(demux, 0);
}
void TDT::ready(int error)
{
eDVBLocalTimeHandler::getInstance()->updateTime(error, chan, ++update_count);
}
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 >= 5 )
{
time_t tptime = parseDVBtime(data[3], data[4], data[5], data[6], data[7]);
eDVBLocalTimeHandler::getInstance()->updateTime(tptime, chan, update_count);
error=0;
return 1;
}
}
return 0;
}
void TDT::start()
{
if ( chan )
{
eDVBTableSpec spec;
spec.pid = TimeAndDateSection::PID;
spec.tid = TimeAndDateSection::TID;
spec.tid_mask = 0xFC;
spec.timeout = TimeAndDateSection::TIMEOUT;
spec.flags= eDVBTableSpec::tfAnyVersion |
eDVBTableSpec::tfHaveTID |
eDVBTableSpec::tfHaveTIDMask |
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);
}
eDVBLocalTimeHandler::~eDVBLocalTimeHandler()
{
instance=0;
for (std::map<iDVBChannel*, channel_data>::iterator it=m_knownChannels.begin(); it != m_knownChannels.end(); ++it)
delete it->second.tdt;
}
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, int update_count )
{
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);
eMainloop::addTimeOffset(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;
bool updated = m_time_ready;
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 &&
updated) // overrride this check on first received TDT
{
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 !!
if ( !update_count )
{
// set rtc to calced transponder time when the first tdt is received on this
// transponder
setRTC(t);
eDebug("[eDVBLocalTimerHandler] update RTC");
}
else
eDebug("[eDVBLocalTimerHandler] don't update RTC");
if ( abs(m_time_difference) > 59 )
{
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();
}
if ( restart_tdt )
{
std::map<iDVBChannel*, channel_data>::iterator it =
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;
}
}
}
void eDVBLocalTimeHandler::DVBChannelAdded(eDVBChannel *chan)
{
if ( chan )
{
// eDebug("[eDVBLocalTimerHandler] add channel %p", chan);
std::pair<std::map<iDVBChannel*, channel_data>::iterator, bool> tmp =
m_knownChannels.insert( std::pair<iDVBChannel*, channel_data>(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);
}
}
void eDVBLocalTimeHandler::DVBChannelStateChanged(iDVBChannel *chan)
{
std::map<iDVBChannel*, channel_data>::iterator it =
m_knownChannels.find(chan);
if ( it != m_knownChannels.end() )
{
int state=0;
chan->getState(state);
if ( state != it->second.m_prevChannelState )
{
switch (state)
{
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;
default: // ignore all other events
return;
}
it->second.m_prevChannelState = state;
}
}
}
|