TimingEventSource.cpp

Go to the documentation of this file.
00001 //Copyright GSI 2012
00002 #include <sstream>
00003 #include <fstream>
00004 #include <malloc.h>
00005 #include <sys/time.h>
00006 
00007 
00008 #include <fesa-core-gsi/RealTime/TimingEventSource.h>
00009 #include <fesa-core-gsi/RealTime/TimingPayload.h>
00010 #include <fesa-core-gsi/Synchronization/TimingContext.h>
00011 #include <fesa-core-gsi/Exception/FesaGSIExceptionDef.h>
00012 #include <fesa-core-gsi/Synchronization/GSICycleDescriptor.h>
00013 #include <fesa-core/Core/FesaDefs.h>
00014 #include <fesa-core/Core/AbstractEquipment.h>
00015 #include <fesa-core/Utilities/ParserElements/EventElement.h>
00016 #include <fesa-core/Utilities/ParserElements/ParserElementDefs.h>
00017 #include <cmw-log/Logger.h>
00018 #include <fesa-core/Diagnostic/Diagnostics.h>
00019 #include <math.h>
00020 
00021 namespace
00022 {
00023 
00024 CMW::Log::Logger& logger = CMW::Log::LoggerFactory::getLogger("FESA.FWK.fesa-core-gsi.RealTime.TimingEventSource");
00025 const std::string diagTopic = fesa::DiagnosticUtils::eventTrackingStr;
00026 
00027 } // namespace
00028 
00029 namespace fesaGSI
00030 {
00031     int TimingEventSource::ourDebugOptions_;
00032     int TimingEventSource::LTIM_HARD_ID_TRANS = -1;
00033 
00034     TimingEventSource::TimingEventSource() :
00035         fesa::AbstractEventSource(fesa::TIMING_EVENT_SOURCE_NAME, fesa::TimingSource)
00036     {
00037         ourDebugOptions_ = getDebugOptions();
00038 
00039         fd_ = TimLibFdInitialize(TimLibDevice_ANY);
00040         if (fd_ == 0)
00041         {
00042             char* ignore = getenv("TimingEventSource_IgnoreHardware");
00043             if (!ignore)
00044             {
00045                 throw GSIException(__FILE__, __LINE__, FESAGSIErrorInitializingTimLib.c_str());
00046             }
00047         }
00048         // Set EventQueueing ON and no timeout
00049         TimLibFdQueue(fd_, 0, 0);
00050 
00051     }
00052 
00053     unsigned int TimingEventSource::getDebugOptions()
00054     {
00055         char* debugStr = getenv("TimingEventSource_DebugOptions");
00056 
00057         if (!debugStr)
00058         {
00059             return 0;
00060         }
00061 
00062         debugStr += strspn(debugStr, " \t"); /* skip white space */
00063 
00064         // we support hex format but not octal, hence strip leading zero's
00065         while (debugStr[0] == '0' && (debugStr[1] != 'x' && debugStr[1] != 'X' && debugStr[1] != '\0'))
00066         {
00067             debugStr += 1;
00068         }
00069         return strtol(debugStr, 0, 0);
00070     }
00071 
00072     TimingEventSource::~TimingEventSource()
00073     {
00074     }
00075 
00076     fesa::RTEvent* TimingEventSource::wait()
00077     {
00078         TimLibError err;
00079         TimLibClass t_class; /* Class of interrupt */
00080         unsigned long equip; /* PTIM CTIM or hardware mask */
00081         unsigned long plnum; /* Ptim line number 1..n or 0 */
00082         TimLibHardware source; /* Hardware source of interrupt */
00083         TimLibTime trigger; /* Time of counters load */
00084         TimLibTime start; /* Time of counters start */
00085         unsigned long ctim; /* CTIM trigger equipment ID */
00086         unsigned long module = 0; /* Module that interrupted */
00087         unsigned long missed = 0; /* Number of missed interrupts */
00088         unsigned long qsize = 0; /* Remaining interrupts on queue */
00089         TgmMachine tgmMachine;
00090         // This loop is necessary in case of error on TimLib call. For errors other
00091         // than TimLibTIMEOUT we have to insert our own delay to avoid to loop
00092         // in TimLibCall very fast consuming all CPU time.
00093         for (;;)
00094         {
00095             fesaGSI::TimingContext* tc = 0;
00096             fesa::RTEventPayload * pTimingPayload = 0;
00097             fesa::RTEvent* theEvent = 0;
00098 
00099             TimLibTime interruptStamp;
00100             unsigned long payload;
00101 
00102             try
00103             {
00104 
00105                 err = TimLibFdWait(fd_, &t_class, &equip, &plnum, &source, &interruptStamp, &trigger, &start, &ctim,
00106                                 &payload, &module, &missed, &qsize, &tgmMachine);
00107 
00108                 if (err == TimLibErrorTIMEOUT)
00109                 {
00110                     //FWK_LOGERROR(ERROR) << "TimingEventSource::wait() TimLibWait returns: " << TimLibErrorToString(err) << endl;
00111                     continue; // try again
00112                 }
00113                 // It's not a TimeOUT : so display the error and insert a sleep
00114                 // to avoid to fall again immedialtely into the TimLibWait and
00115                 // consume all CPU time.
00116                 else if (err != 0)
00117                 {
00118                     //FWK_LOGERROR(ERROR) << "TimingEventSource::wait() TimLibWait returns: " << TimLibErrorToString(err) << endl;
00119                     struct timespec retryDelay = { 2, 0 };
00120                     struct timespec time_left_before_wakeup;
00121                     nanosleep(&retryDelay, &time_left_before_wakeup);
00122                     continue; // try again
00123                 }
00124                 const boost::shared_ptr<fesa::Diagnostics>& diagnostics = fesa::AbstractEquipment::getInstance()->getDiagnostics();
00125                 fesa::DiagnosticUtils::DiagnosticMessage diagMsg;
00126                 diagMsg.side = fesa::DiagnosticUtils::framework;
00127                 diagMsg.source = fesa::DiagnosticUtils::event;
00128                 diagMsg.name = getName();
00129                 diagMsg.msg = "TimLibWait wake-up";
00130                 diagnostics->log(diagTopic, diagMsg);
00131                 // Checking if event was previously registered and retrieving stored information about the event.
00132                 TimingInfo timingInfo;
00133 
00134                 if (t_class == TimLibClassCTIM)
00135                 {
00136 
00137                     std::map<int, TimingInfo>::iterator itr = ctimEventsCol_.find(equip);
00138 
00139                     if (itr == ctimEventsCol_.end())
00140                     {
00141                         std::stringstream buf;
00142                         std::ostringstream errorStrStream;
00143                         errorStrStream << "ERROR: TiminEventSource::wait : received an unexpected event identified by TimingClass";
00144                         LOG_ERROR_IF(logger, errorStrStream.str());
00145                         continue;
00146                     }
00147                     else
00148                     {
00149                         timingInfo = (*itr).second;
00150                     }
00151                 }
00152                 else if (t_class == TimLibClassPTIM)
00153                 {
00154                     std::map<int, TimingInfo>::iterator itr = ltimEventsCol_.find(equip);
00155 
00156                     if (itr == ltimEventsCol_.end())
00157                     {
00158                         std::stringstream buf;
00159                         std::ostringstream errorStrStream;
00160                         errorStrStream << "ERROR: TiminEventSource::wait : received an unexpected event identified by TimingClass";
00161                         LOG_ERROR_IF(logger, errorStrStream.str());
00162                         continue;
00163                     }
00164                     else
00165                     {
00166                         timingInfo = (*itr).second;
00167                     }
00168                 }
00169                 else if (t_class == TimLibClassHARDWARE)
00170                 {
00171                     TimingKey key(equip, module);
00172 
00173                     std::map<TimingKey, TimingInfo>::iterator itr = ltimHardEventsCol_.find(key);
00174 
00175                     if (itr == ltimHardEventsCol_.end())
00176                     {
00177                         std::stringstream buf;
00178                         std::ostringstream errorStrStream;
00179                         errorStrStream << "ERROR: TiminEventSource::wait : received an unexpected event identified by TimingClass";
00180                         LOG_ERROR_IF(logger, errorStrStream.str());
00181                         continue;
00182                     }
00183                     else
00184                     {
00185                         timingInfo = (*itr).second;
00186                     }
00187 
00188                 }
00189 
00190                 interruptStamp.Machine = tgmMachine;
00191 
00192                 pTimingPayload = new TimingPayload(payload);
00193                 fesaGSI::TimingContext* context = new fesaGSI::TimingContext(interruptStamp, payload, timingInfo.forewarning_);
00194                 theEvent = new fesa::RTEvent(timingInfo.concreteName_, context, this);
00195                 // Everything is fine goes out the infinite loop and fires the event
00196 
00197                 diagMsg.msg = "Send RT event";
00198                 diagnostics->log(diagTopic, diagMsg);
00199 
00200                 return theEvent;
00201             }
00202             catch (fesa::FesaException& ex)//this also covers FESACERNExceptions
00203             {
00204                 if (tc != 0)
00205                     delete tc;
00206                 if (pTimingPayload != 0)
00207                     delete pTimingPayload;
00208                 if (theEvent != 0)
00209                     delete theEvent;
00210 
00211                 std::stringstream buf;
00212                 std::ostringstream errorStrStream;
00213                 errorStrStream << "Event was not fired because the following exception occured: " << ex.getMessage();
00214                 LOG_ERROR_IF(logger, errorStrStream.str());
00215             }
00216             catch (...)
00217             {
00218                 if (tc != 0)
00219                     delete tc;
00220                 if (pTimingPayload != 0)
00221                     delete pTimingPayload;
00222                 if (theEvent != 0)
00223                     delete theEvent;
00224 
00225                 std::stringstream buf;
00226                 std::ostringstream errorStrStream;
00227                 errorStrStream << "Event was not fired becausean unknown exception occured.";
00228                 LOG_ERROR_IF(logger, errorStrStream.str());
00229             }
00230         }
00231     }
00232 
00233     void TimingEventSource::connect(boost::shared_ptr<fesa::EventElement>& eventElement)
00234     {
00235         std::string concreteEventName = eventElement->getSourceTypeSpecificData(fesa::TIMING_TAG_CONCRETE_NAME);
00236 
00237         // concreteEventName is formatted like this:
00238         // "BX.WCY200-CT#CTIM#202" or "EX.SCY-MTG#LTIM#16 or EX.SCY-MTG#LTIM-HARD#16"
00239         TimLibClass theTimLibClass;
00240         //size_t posSep0= concreteEventName.find(':');
00241         size_t posSep1 = concreteEventName.find('#');
00242         size_t posSep2 = concreteEventName.rfind('#', concreteEventName.size());
00243         if (posSep1 == std::string::npos || posSep2 == std::string::npos)
00244         {
00245             throw GSIException(__FILE__, __LINE__, FESAGSIErrorWrongTimingName.c_str(), concreteEventName.c_str());
00246         }
00247 
00248         //std::string objectClassName = concreteEventName.substr(posSep0+2, posSep1);
00249         std::string objectClassName = concreteEventName.substr(posSep1 + 1, posSep2 - posSep1 - 1);
00250         if (objectClassName == "CTIM")
00251         {
00252             theTimLibClass = TimLibClassCTIM;
00253         }
00254         else if (objectClassName == "LTIM")
00255         {
00256             theTimLibClass = TimLibClassPTIM;
00257         }
00258         else if (objectClassName == "LTIM-HARD")
00259         {
00260             theTimLibClass = TimLibClassHARDWARE;
00261         }
00262         else
00263         {
00264             throw GSIException(__FILE__, __LINE__, FESAGSIErrorUnknownTimingObjectClassName.c_str(),
00265                             concreteEventName.c_str());
00266         }
00267 
00268         int connectionId = -1;
00269         std::string idStr = concreteEventName.substr(posSep2 + 1);
00270         const char* pStr = idStr.c_str();
00271         if (pStr[0] == '0' && (pStr[1] == 'x' || pStr[1] == 'X'))
00272         {
00273             connectionId = strtol(pStr + 2, 0, 16);
00274         }
00275         else
00276         {
00277             connectionId = atol(pStr);
00278         }
00279 
00280         // By default we use module 0 means the system will decide which device to use
00281         unsigned long module = 0;
00282         //      // In case of LTIM-HARD the connectionId is the hardware mask which is computed from the channel(2^channel).
00283         //      // So we keep the original connectionId into equipId because in any case TimLibWait returns original connectionId
00284         //      int equipId = connectionId;
00285         // In case of TimLibClassHARDWARE: we have to retrieve the ptimObject using the connectionId
00286         if ((theTimLibClass == TimLibClassPTIM) || (theTimLibClass == TimLibClassHARDWARE))
00287         {
00288             unsigned long m; // module
00289             unsigned long c; // channel
00290             unsigned long d; // dimension
00291             TimLibError err = TimLibGetPtimObject(connectionId, &m, &c, &d);
00292             if (err != 0)
00293             {
00294                 throw GSIException(__FILE__, __LINE__, FESAGSIErrorWhileGettingTimingObject.c_str(),
00295                                 concreteEventName.c_str());
00296             }
00297 
00298             // compute the hw mask and overwite connectionId
00299             if (theTimLibClass == TimLibClassHARDWARE)
00300             {
00301                 connectionId = (unsigned long) (pow(2, c));
00302             }
00303             // overwite the module
00304             module = m;
00305         }
00306         else if (theTimLibClass == TimLibClassCTIM)
00307         {
00308             module = TimLibGetModuleForCtim(connectionId);
00309         }
00310 
00311         int equipId = connectionId;
00312         if (theTimLibClass == TimLibClassHARDWARE)
00313         {
00314             equipId *= LTIM_HARD_ID_TRANS;
00315         }
00316 
00317         TimLibError err = TimLibFdConnect(fd_, theTimLibClass, connectionId, module);
00318         if (err != 0)
00319         {
00320             throw GSIException(__FILE__, __LINE__, FESAGSIErrorWhileConnectingTimingEvent.c_str(),
00321                             concreteEventName.c_str());
00322         }
00323 
00324         std::stringstream buf;
00325         std::ostringstream errorStrStream;
00326         errorStrStream << "TimLibConnect: " << concreteEventName << " : theTimLibClass: " << theTimLibClass << " : connectionId: " << connectionId << " : module: " << module;
00327         LOG_ERROR_IF(logger, errorStrStream.str());
00328 
00329         TimingInfo timingInfo;
00330 
00331         timingInfo.concreteName_ = concreteEventName;
00332         timingInfo.forewarning_ = false;
00333 
00334         if (objectClassName == "CTIM")
00335         {
00336             ctimEventsCol_.insert(std::make_pair(connectionId, timingInfo));
00337         }
00338         else if (objectClassName == "LTIM")
00339         {
00340             ltimEventsCol_.insert(std::make_pair(connectionId, timingInfo));
00341         }
00342         else if (objectClassName == "LTIM-HARD")
00343         {
00344             TimingKey key(connectionId, module);
00345             ltimHardEventsCol_.insert(std::make_pair(key, timingInfo));
00346         }
00347 
00348         return;
00349     }
00350 
00351 }//end namespace

Generated on 25 Jan 2013 for fesa-core-gsi by  doxygen 1.6.1