TimingSimulationEventSource.cpp

Go to the documentation of this file.
00001 //Copyright GSI 2012
00002 #include <fesa-core-gsi/RealTime/TimingSimulationEventSource.h>
00003 #include <fesa-core-gsi/Synchronization/TimingSimulationContext.h>
00004 
00005 #include <vector>
00006 #include <fesa-core/Utilities/XMLParser.h>
00007 #include <fesa-core/Diagnostic/FesaLogger.h>
00008 #include <fesa-core/Utilities/ParserElements/EventElement.h>
00009 #include <fesa-core/Utilities/ParserElements/ParserElementDefs.h>
00010 #include <fesa-core/Diagnostic/Diagnostics.h>
00011 
00012 #include <cmw-log/Logger.h>
00013 
00014 
00015 namespace
00016 {
00017 
00018 CMW::Log::Logger& logger = CMW::Log::LoggerFactory::getLogger("FESA.FWK.fesa-core-gsi.RealTime.TimingEventSource");
00019 const std::string diagTopic = fesa::DiagnosticUtils::eventTrackingStr;
00020 
00021 } // namespace
00022 
00023 namespace fesaGSI
00024 {
00025         TimingSimulationEventSource::SimulationEvent::SimulationEvent(std::string& className, CycleConfig& cycle, DomainConfig* domain, long absOff,long relativEventTimeInCycle, EventConfig* eventConfig) :
00026                 delay_(0), absOffset_(absOff), nextEvent_(NULL),eventConfig_(eventConfig)
00027         {
00028 
00029                 className_ = className;
00030                 cycleID_ = cycle.cycleID_;
00031                 cycleName_  = cycle.cycleName_;
00032                 domainName_ = domain->name_;
00033                 relativEventTimeInCycle_ = relativEventTimeInCycle;
00034 
00035                 //TODO: extra condition-behaviour ... to be added later
00036 //              if( cycle.telegramData_ != NULL)
00037 //              {
00038 //                      if(cycle.telegramData_->destination_ != "")
00039 //                      {
00040 //                              std::string temp = domain->name_ + ".DEST." + cycle.telegramData_->destination_;
00041 //                              context->setExtraCondition(temp);
00042 //                      }
00043 //                      if(cycle.telegramData_->particleType_ != "")
00044 //                      {
00045 //                              std::string temp = domain->name_ + ".PARTY." + cycle.telegramData_->particleType_;
00046 //                              context->setExtraCondition(temp);
00047 //                      }
00048 //                      if(cycle.telegramData_->spCon_ != "")
00049 //                      {
00050 //                              std::string temp = domain->name_ + ".SPCON." + cycle.telegramData_->spCon_;
00051 //                              context->setExtraCondition(temp);
00052 //                      }
00053 //              }
00054         }
00055 
00056     TimingSimulationEventSource::TimingSimulationEventSource(const std::string& name,const std::string& timingSimulationConfigFile,fesa::EventSourceType type) : fesa::AbstractEventSource(name,type)
00057     {
00058         timingConfiguration_ = new TimingSimulationConfig(timingSimulationConfigFile);
00059         simulationEventSequence_ = NULL;
00060         eventSequenceBuild_ = false;
00061         fillEventCollection();
00062     }
00063 
00064     TimingSimulationEventSource::~TimingSimulationEventSource()
00065     {
00066         // loop on all the simulation events
00067         SimulationEvent * pEventSequence = simulationEventSequence_;
00068         while (pEventSequence)
00069         {
00070             SimulationEvent * pTmp = pEventSequence;
00071             pEventSequence = pEventSequence->nextEvent_;
00072             delete pTmp;
00073         }
00074         delete timingConfiguration_;
00075     }
00076 
00077     fesa::RTEvent* TimingSimulationEventSource::wait()
00078     {
00079                 if (!eventSequenceBuild_)
00080                 {
00081                         buildEventSequence();
00082                         currentEvent_ = simulationEventSequence_;
00083                         superCycleCount_ = timingConfiguration_->superCycleRepetition_;
00084                 }
00085 
00086                 while (superCycleCount_ != 0)
00087                 {
00088                         if (currentEvent_->delay_)
00089                         { // else: no waiting if the delay is 0
00090                                 time_t sec = currentEvent_->delay_ / 1000;
00091                                 long long nsec = (currentEvent_->delay_ - sec * 1000) * 1000000;
00092                                 //UNIX variants often use a kernel timer resolution (HZ value)
00093                                 //of about 10ms. So it' not possible to manage delays less than 10ms
00094                                 //to wait 10ms you need specify a delay 0 othewise your delay will b 20ms
00095                                 nsec -= 10000000;
00096                                 if (nsec < 0)
00097                                         nsec = 0;
00098                                 struct timespec delay = { sec, nsec }; // ms -> {s, ns}
00099                                 nanosleep(&delay, 0);
00100                         }
00101 
00102                         if (currentEvent_->nextEvent_ == NULL) // the last event in the sequence was reached
00103                         {
00104                                 if(superCycleCount_ != -1)
00105                                         superCycleCount_--;
00106                                 currentEvent_ = simulationEventSequence_;
00107                         }
00108                         else
00109                         {
00110                                 currentEvent_ = currentEvent_->nextEvent_;
00111                         }
00112 
00113                         if (currentEvent_->className_ == "")//event is not registered for any class
00114                         {
00115                 std::stringstream buf;
00116                 std::ostringstream errorStrStream;
00117                 errorStrStream << "| The execution of the event " << currentEvent_->eventConfig_->eventName_ << " was skipped, since there is no class in this fesa-equipment which is triggered by the event |";
00118                 LOG_ERROR_IF(logger, errorStrStream.str());
00119 
00120                                 throw GSIException(__FILE__,__LINE__,FesaGSIUnusedEventSkipped.c_str(),currentEvent_->eventConfig_->eventName_.c_str());
00121                         }
00122 
00123                         std::string fullEventname = currentEvent_->className_+"::"+currentEvent_->eventConfig_->eventName_;
00124 
00125                         //The MuxContext is deleted automatically after usage ... so we have to re-create it per event.
00126                         TimingSimulationContext *context = new TimingSimulationContext(currentEvent_->domainName_,currentEvent_->cycleID_, currentEvent_->cycleName_,currentEvent_->relativEventTimeInCycle_);
00127 
00128                         //set the actual cycle-timestamp (the "now"-stamp))
00129                         context->setCycleTimeStamp();
00130 
00131                         fesa::RTEvent * rtEvent = new fesa::RTEvent(fullEventname, context,this);
00132                         return rtEvent;
00133                 }
00134 
00135                 // timing simulation finished .. enter infinite sleep-loop
00136                 struct timespec delay = { 20, 0 }; // 20sec. like the real timing
00137         std::stringstream buf;
00138         std::ostringstream errorStrStream;
00139         errorStrStream << "|Timing simulation finished. Running infinite sleep-loop now|";
00140         LOG_ERROR_IF(logger, errorStrStream.str());
00141 
00142                 while(true)
00143                 {
00144                         nanosleep(&delay, 0);
00145                 }
00146     }
00147 
00148     void TimingSimulationEventSource::fillEventCollection()
00149     {
00150         std::vector<DomainConfig*>::iterator domainIter;
00151         std::vector<CycleConfig>::iterator cycleIter;
00152         std::vector<EventConfig*>::iterator eventIter;
00153         for (domainIter = timingConfiguration_->timingDomainCol_.begin(); domainIter != timingConfiguration_->timingDomainCol_.end(); domainIter++)
00154         {
00155                 for(cycleIter = (*domainIter)->superCycle_.cycleCol_.begin(); cycleIter != (*domainIter)->superCycle_.cycleCol_.end(); cycleIter++)
00156                 {
00157                         cycleIter->eventSequenceRef_->events_.begin();
00158                                 for (eventIter = cycleIter->eventSequenceRef_->events_.begin(); eventIter != cycleIter->eventSequenceRef_->events_.end(); eventIter++)
00159                                 {
00160                                         std::map<std::string, std::vector<std::string> >::iterator tempIter;
00161                                         tempIter = eventClassRelationCol_.find((*eventIter)->eventName_);
00162                                 if (tempIter == eventClassRelationCol_.end())
00163                                 {//not found --> is a new event --> add to map
00164                                         std::vector<std::string> vec;
00165                                         eventClassRelationCol_.insert(make_pair((*eventIter)->eventName_,vec));
00166                                 }
00167                                 }
00168                 }
00169         }
00170     }
00171 
00172     void TimingSimulationEventSource::connect(boost::shared_ptr<fesa::EventElement>& eventElement)
00173     {
00174         std::string concreteEventName = eventElement->getSourceTypeSpecificData(fesa::TIMING_TAG_CONCRETE_NAME);
00175 
00176         // objectName are formatted like this:
00177         // "ClassName::BX.WCY200-CT#CTIM#202" or "ClassName::EX.SCY-MTG#LTIM#16 or ClassName::EX.SCY-MTG#LTIM-HARD#16"
00178         size_t pos= concreteEventName.find(':');
00179         std::string className = concreteEventName.substr(0, pos);
00180         std::string eventName = concreteEventName.substr(pos+2);
00181 
00182         std::map<std::string, std::vector<std::string> >::iterator iter;
00183         iter = eventClassRelationCol_.find(eventName);
00184         if (iter == eventClassRelationCol_.end())
00185         {//not found --> event is missing in TimingSimulation Config --> throw exception
00186                         throw GSIException(__FILE__,__LINE__,FesaGSIMissingEventConfiguration.c_str(),eventName.c_str());
00187         }
00188         else //event found --> add class
00189         {
00190             (*iter).second.push_back(className);
00191         }
00192     }
00193 
00194     void TimingSimulationEventSource::buildEventSequence()
00195     {
00196         long absStartCycleOffset = 0;
00197 
00198         // calculate super cycle length, it modifies the attribute superCycleLenght_
00199         computeSuperCycleLength();
00200 
00201         // check the timing simulation
00202         checkTimingSimulationConfig();
00203 
00204         std::vector<DomainConfig*>::iterator domainIter;
00205         for (domainIter = timingConfiguration_->timingDomainCol_.begin(); domainIter != timingConfiguration_->timingDomainCol_.end(); domainIter++)
00206         {
00207             if(!(*domainIter)->enable_)
00208                 continue;//jump directly to next element
00209 
00210             absStartCycleOffset += (*domainIter)->superCycle_.shiftDelay_;
00211 
00212             std::vector<CycleConfig>::iterator cycleIter;
00213             for (cycleIter = (*domainIter)->superCycle_.cycleCol_.begin(); cycleIter != (*domainIter)->superCycle_.cycleCol_.end(); cycleIter++)
00214             {
00215                 std::vector<EventConfig*>::iterator eventIter;
00216                 for (eventIter = cycleIter->eventSequenceRef_->events_.begin(); eventIter != cycleIter->eventSequenceRef_->events_.end(); eventIter++)
00217                 {
00218                     createSimulationEvent(*eventIter, absStartCycleOffset, *cycleIter, *domainIter);
00219 
00220                 }// loop on the events
00221 
00222                 absStartCycleOffset += cycleIter->basicPeriodMultiple_ * timingConfiguration_->basicPeriodLengthMs_;
00223 
00224                 if (absStartCycleOffset > superCycleLength_)
00225                     absStartCycleOffset = absStartCycleOffset - superCycleLength_;
00226             } // end loop on cycles
00227 
00228             computeDelays();
00229         }// end loop on timing domains
00230 
00231         eventSequenceBuild_ = true;
00232     }
00233 
00234     void TimingSimulationEventSource::insertSorted(SimulationEvent * newEvent)
00235     {
00236         if (simulationEventSequence_ == NULL)// still empty?
00237         {
00238             simulationEventSequence_ = newEvent;
00239             return;
00240         }
00241 
00242         if (newEvent->absOffset_ <= simulationEventSequence_->absOffset_)// we have to replace the head?
00243         {
00244                 newEvent->nextEvent_ = simulationEventSequence_;
00245             simulationEventSequence_ = newEvent;
00246             return;
00247         }
00248 
00249         SimulationEvent * temp = simulationEventSequence_->nextEvent_;
00250         SimulationEvent * prev = simulationEventSequence_;
00251         while(temp!= NULL)
00252         {
00253                 if(newEvent->absOffset_ <= temp->absOffset_)
00254                 {//insert here
00255                 newEvent->nextEvent_ = temp;
00256                 prev->nextEvent_ = newEvent;
00257                 return;
00258                 }
00259                 else
00260                 {//next one
00261                 prev = temp;
00262                 temp = temp->nextEvent_;
00263                 }
00264         }
00265         prev->nextEvent_ = newEvent;//if we reach the end, we just put it there
00266     }
00267 
00268     // compute the delays for each event from the previous one after having built the entire sequence
00269     void TimingSimulationEventSource::computeDelays()
00270     {
00271         long prevOffset = 0;
00272         SimulationEvent * pEvent = simulationEventSequence_;
00273         while (pEvent)
00274         {
00275             pEvent->delay_ = pEvent->absOffset_ - prevOffset;
00276             prevOffset = pEvent->absOffset_;
00277             pEvent = pEvent->nextEvent_;
00278         }
00279     }
00280 
00281     void TimingSimulationEventSource::computeSuperCycleLength()
00282     {
00283         long maxSuperCycleLenght = 0; // the number of basic periods
00284 
00285         std::vector<DomainConfig*>::iterator timingDomainColIter;
00286         for (timingDomainColIter = timingConfiguration_->timingDomainCol_.begin(); timingDomainColIter != timingConfiguration_->timingDomainCol_.end(); timingDomainColIter++)
00287         {
00288             if(!(*timingDomainColIter)->enable_)
00289                 continue;//jump directly to next element
00290 
00291             std::vector<CycleConfig>::iterator cycleColIter;
00292             for (cycleColIter = (*timingDomainColIter)->superCycle_.cycleCol_.begin();cycleColIter!=(*timingDomainColIter)->superCycle_.cycleCol_.end();cycleColIter++)
00293             {
00294                 maxSuperCycleLenght += cycleColIter->basicPeriodMultiple_;
00295             }
00296         }// end loop on domains
00297         superCycleLength_ = maxSuperCycleLenght * timingConfiguration_->basicPeriodLengthMs_;
00298     }
00299 
00300     void TimingSimulationEventSource::checkTimingSimulationConfig()
00301     {
00302         int scShiftDelayFlag = 0; // In case of multiple domain, only one of them must have shiftDelay 0
00303         bool enabledDomainON = false; // At least one domain should be enabled ON
00304 
00305         std::vector<DomainConfig*>::iterator domainColIter;
00306         for (domainColIter = timingConfiguration_->timingDomainCol_.begin(); domainColIter != timingConfiguration_->timingDomainCol_.end(); domainColIter++)
00307         {
00308             if(!(*domainColIter)->enable_)
00309                 continue;//jump directly to next element
00310 
00311             enabledDomainON |= (*domainColIter)->enable_;
00312 
00313             // count how many delays are equal to 0
00314             if ((*domainColIter)->superCycle_.shiftDelay_ == 0)
00315                 scShiftDelayFlag++;
00316 
00317             long absStartCycleOffset = (*domainColIter)->superCycle_.shiftDelay_;
00318 
00319             std::vector<CycleConfig> cycleCol = (*domainColIter)->superCycle_.cycleCol_;
00320             long lastCycleLength = cycleCol.end()->basicPeriodMultiple_;
00321             long prevStartCycleOffset = (*domainColIter)->superCycle_.shiftDelay_ + superCycleLength_
00322                             - lastCycleLength * timingConfiguration_->basicPeriodLengthMs_;
00323             if (prevStartCycleOffset > superCycleLength_)
00324                 prevStartCycleOffset = prevStartCycleOffset - superCycleLength_;
00325 
00326                 std::vector<CycleConfig>::iterator cycleIter;
00327                 std::vector<EventConfig*>::iterator eventIter;
00328                 for(cycleIter= cycleCol.begin();cycleIter!= cycleCol.end();cycleIter++)
00329                 {
00330                         for(eventIter=cycleIter->eventSequenceRef_->events_.begin();eventIter!=cycleIter->eventSequenceRef_->events_.end();eventIter++)
00331                         {
00332                                 if((*eventIter)->type_ == EventBurst)
00333                                 {
00334                                         EventBurstConfig* burstElement = static_cast<EventBurstConfig*> (*eventIter);
00335 
00336                                                 for (unsigned long m = burstElement->occurrences_; m > 0; m--)
00337                                                 {
00338                                                         long eventAbsOffset = absStartCycleOffset + burstElement->delay_
00339                                                                                         + (burstElement->occurrences_ - m) * burstElement->period_;
00340 
00341                                                         if (eventAbsOffset < 0)
00342                                                                 eventAbsOffset = eventAbsOffset + superCycleLength_;
00343 
00344                                                         long cycleEnd = absStartCycleOffset + cycleIter->basicPeriodMultiple_ * timingConfiguration_->basicPeriodLengthMs_;
00345 
00346                                                         if (((burstElement->delay_ > 0) && (eventAbsOffset > cycleEnd)) || ((burstElement->delay_ < 0) && (eventAbsOffset < prevStartCycleOffset)))
00347                                                         {
00348                                                                 std::stringstream buf;
00349                                                                 buf << burstElement->delay_;
00350                                                                 throw GSIException(__FILE__,__LINE__,FESAGSIErrorEventDelayOutOfRange.c_str(),
00351                                                                                                 burstElement->eventName_.c_str(), cycleIter->cycleName_.c_str(),
00352                                                                                                 buf.str().c_str());
00353                                                         }
00354                                                 }// end occurrences loop
00355                                 }// end if event is burst
00356                         }// end loop on events
00357                 }// end loop cycles
00358 
00359             if (enabledDomainON == false)
00360                         throw GSIException(__FILE__,__LINE__,FESAGSIErrorNoneDomainEnabled.c_str());
00361 
00362             if (scShiftDelayFlag > 1)
00363                 throw GSIException(__FILE__,__LINE__,FESAGSIErrorMoreThanOneDomainShift0.c_str());
00364         }// end loop domains
00365     }
00366 
00367     void TimingSimulationEventSource::createSimulationEvent(EventConfig *config, long absStartCycleOffset, CycleConfig& cycle, DomainConfig* domain)
00368        {
00369            long eventPeriod = 0;
00370            unsigned long eventOccurence = 1;
00371 
00372            EventBurstConfig* burstElement = NULL;
00373            if (config->type_ == EventBurst)
00374            {
00375                burstElement = static_cast<EventBurstConfig*> (config);
00376                eventOccurence = burstElement->occurrences_;
00377                eventPeriod = burstElement->period_;
00378            }
00379 
00380            for (unsigned i = eventOccurence; i > 0; i--)
00381            { // only in case of "burst" this value can be bigger than 1
00382                long eventAbsOffset = absStartCycleOffset + config->delay_ + (eventOccurence - i) * eventPeriod;
00383                long relativEventTimeInCycle = config->delay_+ (eventOccurence - i) * eventPeriod;
00384                // checking whether the delay specified is within the current cycle or the previous one in case negative one:
00385                if (eventAbsOffset < 0)
00386                    eventAbsOffset = eventAbsOffset + superCycleLength_;
00387                else if (eventAbsOffset > superCycleLength_)
00388                {
00389                    eventAbsOffset = eventAbsOffset - superCycleLength_;
00390                }
00391 
00392                //Check if event is used by Fesa-Equipment (connect triggered)
00393                std::map<std::string, std::vector<std::string> >::iterator iter;
00394                iter = eventClassRelationCol_.find(config->eventName_);
00395                if (iter->second.size() != 0)
00396                {//there are classes, using this sim-event
00397                            std::vector<std::string>::iterator classIter;
00398                            for(classIter = iter->second.begin();classIter != iter->second.end();classIter++)
00399                            {
00400                                    //multiply event for each class which needs it
00401                                    SimulationEvent * simEvent = new SimulationEvent(*classIter,cycle,domain, eventAbsOffset,relativEventTimeInCycle,config);
00402                                    insertSorted(simEvent);
00403                            }
00404                }
00405                else//no classes defined to use this event
00406                {
00407                    //event added anyway (without classname) ... error will be thrown later, on execution of the unused event
00408                    std::string empty = "";
00409                    SimulationEvent * simEvent = new SimulationEvent(empty,cycle,domain, eventAbsOffset,relativEventTimeInCycle,config);
00410                    insertSorted(simEvent);
00411                }
00412            }
00413        }
00414 }//end namespace

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