TimerEventSource.cpp

Go to the documentation of this file.
00001 // Copyright CERN 2012 - Developed in collaboration with GSI
00002 
00003 #include <fesa-core/RealTime/TimerEventSource.h>
00004 
00005 #include <fesa-core/RealTime/RTEvent.h>
00006 #include <fesa-core/Synchronization/NoneContext.h>
00007 #include <fesa-core/Utilities/ParserElements.h>
00008 #include <fesa-core/Utilities/ParserElements/TimerEventElement.h>
00009 #include <fesa-core/Utilities/ParserElements/ParserElementDefs.h>
00010 #include <sstream>
00011 
00012 #include <cmw-log/Logger.h>
00013 
00014 #include <climits>
00015 #include <cerrno>
00016 #include <ostream>
00017 
00018 namespace
00019 {
00020 CMW::Log::Logger& logger = CMW::Log::LoggerFactory::getLogger("FESA.FWK.fesa-core.RealTime.TimerEventSource");
00021 }
00022 
00023 namespace fesa
00024 {
00025 /*
00026  * \class TimerEventSource
00027  * \brief TimerEventSource is a particular event-source which requires a dedicated source
00028  * per concrete-event. This choice greatly simplifies the multiple period handling
00029  * by instantiating one thread per timer period, means per timer concrete-event.
00030  * This specific implementation is under responsability of the TimerEventSource class.
00031  * From outside point of view, only one Timer event-source is defined and accessible.
00032  * TIMER_EVENT_SOURCE_NAME/ DEFAULT_EVENT_SOURCE_KEY
00033  *
00034  * This mechanism requires to override the addRTScheduler method in order to register
00035  * the scheduler within the appropriate occurence of the timer event-source.
00036  */
00037 
00038 TimerEventSource::TimerEventSource() :
00039     AbstractEventSource(TIMER_EVENT_SOURCE_NAME, TimerSource),
00040     totalDelay_(0)
00041 {
00042 }
00043 
00044 TimerEventSource::~TimerEventSource()
00045 {
00046 }
00047 
00048 void TimerEventSource::connect(boost::shared_ptr<fesa::EventElement>& eventElement)
00049 {
00050     int32_t period;
00051         std::stringstream converterStream(eventElement->getSourceTypeSpecificData(TIMER_TAG_PERIOD));
00052         converterStream >> period;
00053 
00054     if (period == 0)
00055     {
00056         throw FesaBadParameterException(__FILE__, __LINE__, FesaErrorWrongTimerPeriod.c_str(), eventElement->getLogicalName().c_str());
00057     }
00058     //add info to the vectors
00059     eventNamesCol_.push_back(eventElement->getConcreteName());
00060     eventDelaysCol_.push_back(period);
00061     eventTotalDelaysCol_.push_back(period);
00062     eventsFired_.push_back(0);
00063 }
00064 
00065 RTEvent* TimerEventSource::wait()
00066 {
00067     if (eventsToFire_.size() > 0)
00068     {
00069         return fireNextEvent();
00070     }
00071     struct timespec thePeriod;
00072 
00073     int64_t minimum = LLONG_MAX;
00074     int64_t period = 0;
00075     // find the closest event to fire
00076     for (uint32_t i = 0; i < eventTotalDelaysCol_.size(); i++)
00077     {
00078         if ((eventTotalDelaysCol_[i] - totalDelay_) < minimum)
00079         {
00080             minimum = eventTotalDelaysCol_[i] - totalDelay_;
00081             period = eventTotalDelaysCol_[i] - totalDelay_;
00082             
00083             while (eventsToFire_.size() > 0)
00084             {
00085                 eventsToFire_.pop_front();
00086             }
00087             
00088             eventsToFire_.push_back(i);
00089         }
00090     }
00091 
00092     // update global table
00093     totalDelay_ += period;
00094     for (uint32_t i = 0; i < eventsToFire_.size(); i++)
00095     {
00096         eventTotalDelaysCol_[eventsToFire_[i]] += eventDelaysCol_[eventsToFire_[i]];
00097     }
00098     
00099     int32_t sec = static_cast<int32_t>(period) / 1000; // number of seconds since period is expressed in ms
00100     int32_t nsec = 0;
00101     if ((nsec = static_cast<int32_t>(period) % 1000)) // check remainder
00102     {
00103         nsec *= (int32_t) 1E6; // convert remainder into ns
00104     }
00105     thePeriod.tv_sec = sec;
00106     thePeriod.tv_nsec = nsec;
00107     int32_t ret;
00108     do
00109     {
00110         ret = nanosleep(&thePeriod, &thePeriod);
00111     }
00112     while ((ret == -1) && (errno == EINTR)); // check if interrupted by a signal
00113 
00114     return fireNextEvent();
00115 }
00116 
00117 RTEvent* TimerEventSource::fireNextEvent()
00118 {
00119     int32_t eventIndex = eventsToFire_.front();
00120     eventsToFire_.pop_front();
00121     RTEvent* rtEvt = new RTEvent(eventNamesCol_[eventIndex], new NoneContext(), this);
00122     eventsFired_[eventIndex]++;
00123     if (logger.isLoggable(CMW::Log::Level::LL_TRACE))
00124     {
00125         std::ostringstream msg;
00126         msg << "firing event " << eventNamesCol_[eventIndex];
00127         LOG_TRACE_IF(logger, msg.str());
00128     }
00129     return rtEvt;
00130 }
00131 
00132 } // fesa

Generated on 18 Jan 2013 for Fesa by  doxygen 1.6.1