From a33ff213255db7f59090f70235ec06c502e2a2ce Mon Sep 17 00:00:00 2001 From: Andreas Monzner Date: Thu, 30 Jun 2005 14:52:13 +0000 Subject: [PATCH] add dvb time handling with transponder time correction algo.. this use a rtc, when avail, mainloop changes for set linux time --- lib/base/ebase.cpp | 123 ++++++++++++++++++++++++++++--------------- lib/base/ebase.h | 47 ++++++++++++----- lib/dvb/Makefile.am | 4 +- lib/dvb/dvb.cpp | 20 +++++++ lib/dvb/dvb.h | 12 ++++- lib/dvb/esection.cpp | 5 +- lib/dvb/pmt.cpp | 5 +- main/enigma.cpp | 7 +-- 8 files changed, 157 insertions(+), 66 deletions(-) diff --git a/lib/base/ebase.cpp b/lib/base/ebase.cpp index 465cea9f..19444d20 100644 --- a/lib/base/ebase.cpp +++ b/lib/base/ebase.cpp @@ -5,6 +5,7 @@ #include #include +#include eSocketNotifier::eSocketNotifier(eMainloop *context, int fd, int requested, bool startnow): context(*context), fd(fd), state(0), requested(requested) { @@ -43,15 +44,32 @@ void eTimer::start(long msek, bool singleShot) bActive = true; bSingleShot = singleShot; interval = msek; - gettimeofday(&nextActivation, 0); -// eDebug("this = %p\nnow sec = %d, usec = %d\nadd %d msec", this, nextActivation.tv_sec, nextActivation.tv_usec, msek); + gettimeofday(&nextActivation, 0); + nextActivation.tv_sec -= context.getTimerOffset(); nextActivation += (msek<0 ? 0 : msek); +// eDebug("this = %p\nnow sec = %d, usec = %d\nadd %d msec", this, nextActivation.tv_sec, nextActivation.tv_usec, msek); +// eDebug("next Activation sec = %d, usec = %d", nextActivation.tv_sec, nextActivation.tv_usec ); + context.addTimer(this); +} + +void eTimer::startLongTimer( int seconds ) +{ + if (bActive) + stop(); + + bActive = bSingleShot = true; + interval = 0; + gettimeofday(&nextActivation, 0); + nextActivation.tv_sec -= context.getTimerOffset(); +// eDebug("this = %p\nnow sec = %d, usec = %d\nadd %d msec", this, nextActivation.tv_sec, nextActivation.tv_usec, msek); + if ( seconds > 0 ) + nextActivation.tv_sec += seconds; // eDebug("next Activation sec = %d, usec = %d", nextActivation.tv_sec, nextActivation.tv_usec ); context.addTimer(this); } void eTimer::stop() -{ +{ if (bActive) { bActive=false; @@ -67,7 +85,7 @@ void eTimer::changeInterval(long msek) nextActivation -= interval; // sub old interval } else - bActive=true; // then activate Timer + bActive=true; // then activate Timer interval = msek; // set new Interval nextActivation += interval; // calc nextActivation @@ -75,12 +93,8 @@ void eTimer::changeInterval(long msek) context.addTimer(this); // add Timer to context TimerList } -void eTimer::activate() // Internal Function... called from eApplication +void eTimer::activate() // Internal Funktion... called from eApplication { - timeval now; - gettimeofday(&now, 0); -// eDebug("this = %p\nnow sec = %d, usec = %d\nnextActivation sec = %d, usec = %d", this, now.tv_sec, now.tv_usec, nextActivation.tv_sec, nextActivation.tv_usec ); -// eDebug("Timer emitted"); context.removeTimer(this); if (!bSingleShot) @@ -94,7 +108,27 @@ void eTimer::activate() // Internal Function... called from eApplication /*emit*/ timeout(); } +inline void eTimer::recalc( int offset ) +{ + nextActivation.tv_sec += offset; +} + // mainloop +ePtrList eMainloop::existing_loops; + +void eMainloop::setTimerOffset( int difference ) +{ + singleLock s(recalcLock); + if (!TimerList) + timer_offset=0; + else + { + if ( timer_offset ) + eDebug("time_offset %d avail.. add new offset %d than new is %d", + timer_offset, difference, timer_offset+difference); + timer_offset+=difference; + } +} void eMainloop::addSocketNotifier(eSocketNotifier *sn) { @@ -115,25 +149,25 @@ void eMainloop::processOneEvent() we should do this all better - we know how long the poll last, so we know which timers should fire. Problem is that a timer handler could have required so much time that another timer fired. - + A probably structure could look - + while (1) { time = gettimeofday() timeout = calculate_pending_timers(time); - + doPoll(timeout or infinite); - + if (poll_had_results) handle_poll_handler(); else fire_timers(time + timeout) } - + the gettimeofday() call is required because fire_timers could last more than nothing. - + when poll did no timeout, we don't handle timers, as this will be done in the next iteration (without adding overhead - we had to get the new time anyway @@ -142,13 +176,18 @@ void eMainloop::processOneEvent() // first, process pending timers... long usec=0; + if ( TimerList ) + doRecalcTimers(); while (TimerList && (usec = timeout_usec( TimerList.begin()->getNextActivation() ) ) <= 0 ) + { TimerList.begin()->activate(); + doRecalcTimers(); + } - // build the poll aray int fdAnz = notifiers.size(); - pollfd* pfd = new pollfd[fdAnz]; // make new pollfd array + pollfd pfd[fdAnz]; +// fill pfd array std::map::iterator it(notifiers.begin()); for (int i=0; i < fdAnz; i++, it++) { @@ -157,10 +196,11 @@ void eMainloop::processOneEvent() } // to the poll. When there are no timers, we have an infinite timeout - int ret=poll(pfd, fdAnz, TimerList ? usec / 1000 : -1); // convert to us + int ret=poll(pfd, fdAnz, TimerList ? usec / 1000 : -1); // convert to ms if (ret>0) { + // eDebug("bin aussem poll raus und da war was"); for (int i=0; i < fdAnz ; i++) { if( notifiers.find(pfd[i].fd) == notifiers.end()) @@ -171,68 +211,58 @@ void eMainloop::processOneEvent() if ( pfd[i].revents & req ) { notifiers[pfd[i].fd]->activate(pfd[i].revents); - if (!--ret) break; - } else if (pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL)) - eFatal("poll: unhandled POLLERR/HUP/NVAL for fd %d(%d) -> FIX YOUR CODE", pfd[i].fd,pfd[i].revents); + } + else if (pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL)) + eDebug("poll: unhandled POLLERR/HUP/NVAL for fd %d(%d)", pfd[i].fd,pfd[i].revents); } - } else if (ret<0) + } + else if (ret<0) { - /* when we got a signal, we get EINTR. we do not care, + /* when we got a signal, we get EINTR. we do not care, because we check current time in timers anyway. */ if (errno != EINTR) - eDebug("poll made error (%m)"); - } - - // check timer... - while ( TimerList && timeout_usec( TimerList.begin()->getNextActivation() ) <= 0 ) - TimerList.begin()->activate(); - - delete [] pfd; + eDebug("poll made error"); + } } - int eMainloop::exec() { if (!loop_level) { app_quit_now = false; + app_exit_loop = false; enter_loop(); } return retval; } - /* use with care! better: don't use it anymore. it was used for gui stuff, but - doesn't allow multiple paths (or active dialogs, if you want it that way.) */ void eMainloop::enter_loop() { loop_level++; - // Status der vorhandenen Loop merken bool old_exit_loop = app_exit_loop; - + app_exit_loop = false; while (!app_exit_loop && !app_quit_now) - { processOneEvent(); - } // wiederherstellen der vorherigen app_exit_loop app_exit_loop = old_exit_loop; - loop_level--; + --loop_level; if (!loop_level) { - // do something here on exit the last loop + // do something here on exit the last loop } } void eMainloop::exit_loop() // call this to leave the current loop { - app_exit_loop = true; + app_exit_loop = true; } void eMainloop::quit( int ret ) // call this to leave all loops @@ -241,4 +271,15 @@ void eMainloop::quit( int ret ) // call this to leave all loops app_quit_now = true; } +inline void eMainloop::doRecalcTimers() +{ + singleLock s(recalcLock); + if ( timer_offset ) + { + for (ePtrList::iterator it(TimerList); it != TimerList.end(); ++it ) + it->recalc( timer_offset ); + timer_offset=0; + } +} + eApplication* eApp = 0; diff --git a/lib/base/ebase.h b/lib/base/ebase.h index 3bdd705c..aaabd30d 100644 --- a/lib/base/ebase.h +++ b/lib/base/ebase.h @@ -176,6 +176,8 @@ class eTimer; // werden in einer mainloop verarbeitet class eMainloop { + friend class eTimer; + friend class eSocketNotifier; std::map notifiers; ePtrList TimerList; bool app_exit_loop; @@ -183,22 +185,37 @@ class eMainloop int loop_level; void processOneEvent(); int retval; + int timer_offset; + pthread_mutex_t recalcLock; + inline void doRecalcTimers(); + inline void addSocketNotifier(eSocketNotifier *sn); + inline void removeSocketNotifier(eSocketNotifier *sn); + inline void addTimer(eTimer* e) { TimerList.insert_in_order(e); } + inline void removeTimer(eTimer* e) { TimerList.remove(e); } public: - eMainloop():app_quit_now(0),loop_level(0),retval(0){ } - void addSocketNotifier(eSocketNotifier *sn); - void removeSocketNotifier(eSocketNotifier *sn); - void addTimer(eTimer* e) { TimerList.insert_in_order(e); } - void removeTimer(eTimer* e) { TimerList.remove(e); } - + static ePtrList existing_loops; + eMainloop() + :app_quit_now(0),loop_level(0),retval(0),timer_offset(0) + { + existing_loops.push_back(this); + pthread_mutex_init(&recalcLock, 0); + } + ~eMainloop() + { + existing_loops.remove(this); + pthread_mutex_destroy(&recalcLock); + } int looplevel() { return loop_level; } - + int exec(); // recursive enter the loop void quit(int ret=0); // leave all pending loops (recursive leave()) void enter_loop(); void exit_loop(); + void setTimerOffset( int ); + int getTimerOffset() { return timer_offset; } + bool isAppQuitNowSet() { return app_quit_now; } }; - /** * \brief The application class. * @@ -227,11 +244,13 @@ public: */ class eTimer { + friend class eMainloop; eMainloop &context; timeval nextActivation; long interval; bool bSingleShot; bool bActive; + inline void recalc(int); public: /** * \brief Constructs a timer. @@ -239,19 +258,19 @@ public: * The timer is not yet active, it has to be started with \c start. * \param context The thread from which the signal should be emitted. */ - eTimer(eMainloop *context = eApp): context(*context), bActive(false) { } - ~eTimer() { if (bActive) stop(); } + eTimer(eMainloop *context=eApp): context(*context), bActive(false) { } + ~eTimer() { if (bActive) stop(); } PSignal0 timeout; void activate(); - bool isActive() { return bActive; } + bool isActive() { return bActive; } timeval &getNextActivation() { return nextActivation; } - void start(long msec, bool singleShot=false); + void start(long msec, bool b=false); void stop(); void changeInterval(long msek); - bool operator<(const eTimer& t) const { return nextActivation < t.nextActivation; } + bool operator<(const eTimer& t) const { return nextActivation < t.nextActivation; } + void startLongTimer( int seconds ); }; - #endif diff --git a/lib/dvb/Makefile.am b/lib/dvb/Makefile.am index 2a1402bb..857f5001 100644 --- a/lib/dvb/Makefile.am +++ b/lib/dvb/Makefile.am @@ -4,5 +4,5 @@ INCLUDES = \ noinst_LIBRARIES = libenigma_dvb.a libenigma_dvb_a_SOURCES = dvb.cpp demux.cpp frontend.cpp esection.cpp db.cpp \ - sec.cpp scan.cpp crc32.cpp pmt.cpp decoder.cpp eit.cpp rotor_calc.cpp - + sec.cpp scan.cpp crc32.cpp pmt.cpp decoder.cpp eit.cpp rotor_calc.cpp \ + epgcache.cpp dvbtime.cpp diff --git a/lib/dvb/dvb.cpp b/lib/dvb/dvb.cpp index e0df1dc1..f1f5580a 100644 --- a/lib/dvb/dvb.cpp +++ b/lib/dvb/dvb.cpp @@ -321,6 +321,7 @@ RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *c { eDebug("add channel %p", ch); m_active_channels.push_back(active_channel(chid, ch)); + /* emit */ m_channelAdded(ch); return 0; } @@ -333,6 +334,7 @@ RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch) { i = m_active_channels.erase(i); ++cnt; + /* emit */ m_channelRemoved(ch); } else ++i; } @@ -342,6 +344,24 @@ RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch) return -ENOENT; } +RESULT eDVBResourceManager::connectChannelAdded(const Slot1 &channelAdded, ePtr &connection) +{ + connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded)); + return 0; +} + +RESULT eDVBResourceManager::connectChannelRemoved(const Slot1 &channelRemoved, ePtr &connection) +{ + connection = new eConnection((eDVBResourceManager*)this, m_channelRemoved.connect(channelRemoved)); + return 0; +} + +RESULT eDVBResourceManager::connectChannelRunning(const Slot1 &channelRunning, ePtr &connection) +{ + connection = new eConnection((eDVBResourceManager*)this, m_channelRunning.connect(channelRunning)); + return 0; +} + DEFINE_REF(eDVBChannel); eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend, eDVBAllocatedDemux *demux): m_state(state_idle), m_mgr(mgr) diff --git a/lib/dvb/dvb.h b/lib/dvb/dvb.h index a4652e81..34c55492 100644 --- a/lib/dvb/dvb.h +++ b/lib/dvb/dvb.h @@ -132,10 +132,14 @@ class eDVBResourceManager: public iObject ePtr m_list; ePtr m_sec; static eDVBResourceManager *instance; - + friend class eDVBChannel; RESULT addChannel(const eDVBChannelID &chid, eDVBChannel *ch); RESULT removeChannel(eDVBChannel *ch); + + Signal1 m_channelAdded; + Signal1 m_channelRemoved; + Signal1 m_channelRunning; public: eDVBResourceManager(); virtual ~eDVBResourceManager(); @@ -156,6 +160,9 @@ public: RESULT allocateRawChannel(ePtr &channel); RESULT allocatePVRChannel(int caps); + RESULT connectChannelAdded(const Slot1 &channelAdded, ePtr &connection); + RESULT connectChannelRemoved(const Slot1 &channelRemoved, ePtr &connection); + RESULT connectChannelRunning(const Slot1 &channelRemoved, ePtr &connection); }; class eDVBChannel: public iDVBChannel, public Object @@ -181,7 +188,8 @@ public: /* only for managed channels - effectively tunes to the channelid. should not be used... */ RESULT setChannel(const eDVBChannelID &id); - + eDVBChannelID getChannelID() { return m_channel_id; } + RESULT connectStateChange(const Slot1 &stateChange, ePtr &connection); RESULT getState(int &state); diff --git a/lib/dvb/esection.cpp b/lib/dvb/esection.cpp index 6f634ae1..a80168b5 100644 --- a/lib/dvb/esection.cpp +++ b/lib/dvb/esection.cpp @@ -22,8 +22,7 @@ void eGTable::sectionRead(const __u8 *d) void eGTable::timeout() { - printf("timeout!\n"); -// eDebug("timeout!"); + eDebug("timeout!"); m_reader->stop(); ready = 1; error = -1; @@ -58,7 +57,7 @@ RESULT eGTable::start(iDVBSectionReader *reader, const eDVBTableSpec &table) if (m_table.flags & eDVBTableSpec::tfHaveTID) { mask.data[0] = m_table.tid; - mask.mask[0] = 0xFF; + mask.mask[0] = mask.pid == 0x14 ? 0xFC : 0xFF; } if (m_table.flags & eDVBTableSpec::tfHaveTIDExt) diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp index 3f9ac7f7..c1ac5dd8 100644 --- a/lib/dvb/pmt.cpp +++ b/lib/dvb/pmt.cpp @@ -27,8 +27,11 @@ void eDVBServicePMTHandler::channelStateChanged(iDVBChannel *channel) serviceEvent(eventTuned); if (m_demux) - { + { eDebug("ok ... now we start!!"); + + /* emit */ m_resourceManager->m_channelRunning(channel); + m_PAT.begin(eApp, eDVBPATSpec(), m_demux); } } diff --git a/main/enigma.cpp b/main/enigma.cpp index 217d71b6..21c1d30a 100644 --- a/main/enigma.cpp +++ b/main/enigma.cpp @@ -90,6 +90,7 @@ void keyEvent(const eRCKey &key) #include #include #include +#include class eMain: public eApplication, public Object { @@ -97,9 +98,9 @@ class eMain: public eApplication, public Object ePtr m_mgr; ePtr m_dvbdb; - + ePtr m_locale_time_handler; ePtr m_scan; - + public: eMain() { @@ -108,7 +109,7 @@ public: /* TODO: put into init */ m_dvbdb = new eDVBDB(); m_mgr = new eDVBResourceManager(); - + m_locale_time_handler = new eDVBLocalTimeHandler(); m_mgr->setChannelList(m_dvbdb); // m_scan = new eComponentScan(); -- 2.30.2