#include <errno.h>
#include <lib/base/eerror.h>
+#include <lib/base/elock.h>
eSocketNotifier::eSocketNotifier(eMainloop *context, int fd, int requested, bool startnow): context(*context), fd(fd), state(0), requested(requested)
{
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;
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
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)
/*emit*/ timeout();
}
+inline void eTimer::recalc( int offset )
+{
+ nextActivation.tv_sec += offset;
+}
+
// mainloop
+ePtrList<eMainloop> 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)
{
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
// 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<int,eSocketNotifier*>::iterator it(notifiers.begin());
for (int i=0; i < fdAnz; i++, it++)
{
}
// 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())
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
app_quit_now = true;
}
+inline void eMainloop::doRecalcTimers()
+{
+ singleLock s(recalcLock);
+ if ( timer_offset )
+ {
+ for (ePtrList<eTimer>::iterator it(TimerList); it != TimerList.end(); ++it )
+ it->recalc( timer_offset );
+ timer_offset=0;
+ }
+}
+
eApplication* eApp = 0;
// werden in einer mainloop verarbeitet
class eMainloop
{
+ friend class eTimer;
+ friend class eSocketNotifier;
std::map<int, eSocketNotifier*> notifiers;
ePtrList<eTimer> TimerList;
bool app_exit_loop;
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<eMainloop> 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.
*
*/
class eTimer
{
+ friend class eMainloop;
eMainloop &context;
timeval nextActivation;
long interval;
bool bSingleShot;
bool bActive;
+ inline void recalc(int);
public:
/**
* \brief Constructs a timer.
* 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<void> 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
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
{
eDebug("add channel %p", ch);
m_active_channels.push_back(active_channel(chid, ch));
+ /* emit */ m_channelAdded(ch);
return 0;
}
{
i = m_active_channels.erase(i);
++cnt;
+ /* emit */ m_channelRemoved(ch);
} else
++i;
}
return -ENOENT;
}
+RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
+{
+ connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
+ return 0;
+}
+
+RESULT eDVBResourceManager::connectChannelRemoved(const Slot1<void,eDVBChannel*> &channelRemoved, ePtr<eConnection> &connection)
+{
+ connection = new eConnection((eDVBResourceManager*)this, m_channelRemoved.connect(channelRemoved));
+ return 0;
+}
+
+RESULT eDVBResourceManager::connectChannelRunning(const Slot1<void,iDVBChannel*> &channelRunning, ePtr<eConnection> &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)
ePtr<iDVBChannelList> m_list;
ePtr<iDVBSatelliteEquipmentControl> m_sec;
static eDVBResourceManager *instance;
-
+
friend class eDVBChannel;
RESULT addChannel(const eDVBChannelID &chid, eDVBChannel *ch);
RESULT removeChannel(eDVBChannel *ch);
+
+ Signal1<void,eDVBChannel*> m_channelAdded;
+ Signal1<void,eDVBChannel*> m_channelRemoved;
+ Signal1<void,iDVBChannel*> m_channelRunning;
public:
eDVBResourceManager();
virtual ~eDVBResourceManager();
RESULT allocateRawChannel(ePtr<iDVBChannel> &channel);
RESULT allocatePVRChannel(int caps);
+ RESULT connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection);
+ RESULT connectChannelRemoved(const Slot1<void,eDVBChannel*> &channelRemoved, ePtr<eConnection> &connection);
+ RESULT connectChannelRunning(const Slot1<void,iDVBChannel*> &channelRemoved, ePtr<eConnection> &connection);
};
class eDVBChannel: public iDVBChannel, public Object
/* 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<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection);
RESULT getState(int &state);
void eGTable::timeout()
{
- printf("timeout!\n");
-// eDebug("timeout!");
+ eDebug("timeout!");
m_reader->stop();
ready = 1;
error = -1;
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)
serviceEvent(eventTuned);
if (m_demux)
- {
+ {
eDebug("ok ... now we start!!");
+
+ /* emit */ m_resourceManager->m_channelRunning(channel);
+
m_PAT.begin(eApp, eDVBPATSpec(), m_demux);
}
}
#include <lib/dvb/idvb.h>
#include <lib/dvb/dvb.h>
#include <lib/dvb/db.h>
+#include <lib/dvb/dvbtime.h>
class eMain: public eApplication, public Object
{
ePtr<eDVBResourceManager> m_mgr;
ePtr<eDVBDB> m_dvbdb;
-
+ ePtr<eDVBLocalTimeHandler> m_locale_time_handler;
ePtr<eComponentScan> m_scan;
-
+
public:
eMain()
{
/* 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();