4 Diac中E_CYCLE模块源码分析
E_CYCLE的源码分析
一 E_CYCLE的功能
输入事件接口:START、STOP ,输出事件接口EO
数据输入接口:DT
START是开启定时事件,STOP结束定时事件,EO是时间到了触发的事件,DT是配置时间间隔参数,数据类型为字符串类型。
举例:DT输入T#10MS,则10MS触发一次EO事件
二 源码分析
该源码主要包含四个文件E_CYCLE.h、E_CYCLE.cpp和timedfb.h、timedfb.cpp
首先分析E_CYCLE.h文件,可以看出E_CYCLE这个类继承了CTimeFB类,E_CYCLE类继承了CTimeFB类的功能,包括定时功能块的执行逻辑。因此转定义到类CtimeFB。
#ifndef _E_CYCLE_H_ #define _E_CYCLE_H_ #include "../timedfb.h" /*! \brief Implementation of the E_CYCLE FB. */ class E_CYCLE : public CTimedFB{ DECLARE_FIRMWARE_FB(E_CYCLE) private: public: E_CYCLE(const CStringDictionary::TStringId paInstanceNameId, CResource *paSrcRes) : CTimedFB( paInstanceNameId, paSrcRes, e_Periodic){ } virtual ~E_CYCLE() {} }; #endif /*E_CYCLE_H_*/ 以下为CtimeFB的定义文件(timedfb.h),其中给出了具体事件执行函数executeEvent()。 #ifndef _TIMEDFB_H_ #define _TIMEDFB_H_ #include "../core/esfb.h" #include "../arch/timerha.h" #include "../core/resource.h" /*!\brief Base class for timed function block like E_CYCLE or E_DELAY providing this interface */ class CTimedFB : public CEventSourceFB{ private: protected: static const SFBInterfaceSpec scm_stFBInterfaceSpec; static const CStringDictionary::TStringId scm_aunEINameIds[]; static const TDataIOID scm_anEIWith[]; static const TForteInt16 scm_anEIWithIndexes[]; static const CStringDictionary::TStringId scm_aunEONameIds[]; static const TForteInt16 scm_anEOWithIndexes[]; static const CStringDictionary::TStringId scm_aunDINameIds[]; static const CStringDictionary::TStringId scm_aunDIDataTypeNameIds[]; static const TEventID csm_nEventSTARTID = 0; static const TEventID csm_nEventSTOPID = 1; static const TEventID csm_nEOID = 0; FORTE_FB_DATA_ARRAY(1,1,0, 0); bool mActive; //!> flag to indicate that the timed fb is currently active STimedFBListEntry mTimeListEntry; //!> The Timer list entry of this timed FB /*!\brief execute the input events of timed FBs as far it is possible * * Derived Timed FBs only normaly need only the start event es this is different for each timed FB type (e.g. periodic vs. onetimeshot) */ virtual void executeEvent(int pa_nEIID); CIEC_TIME& DT() { return *static_cast<CIEC_TIME*>(getDI(0)); } public: CTimedFB(const CStringDictionary::TStringId paInstanceNameId, CResource *paSrcRes, ETimerActivationType paType); virtual ~CTimedFB() {}; virtual EMGMResponse changeFBExecutionState(EMGMCommandType pa_unCommand); }; #endif /*TIMEDFB_H_*/
以下为executeEvent函数转定义后timedfb.cpp文件部分代码,可以看出具体执行操作,根据传入的当前执行事件ID号(pa_nEIID),跳转swich分支语句判断。其中mActive为标志位,表示定时FB当前处于活动状态。其中mActive初始化为False,当START接口接收到事件时,执行getTimer().registerTimerFB(&mTimeListEntry,DT()),这里设置触发事件间隔。
CTimedFB::CTimedFB(const CStringDictionary::TStringId paInstanceNameId, CResource *paSrcRes, ETimerActivationType paType) : CEventSourceFB( paSrcRes, &scm_stFBInterfaceSpec, paInstanceNameId, m_anFBConnData, m_anFBVarsData){ setEventChainExecutor(paSrcRes->getResourceEventExecution()); mActive = false; mTimeListEntry.mTimeOut = 0; mTimeListEntry.mInterval = 0; mTimeListEntry.mNext = 0; mTimeListEntry.mType = paType; mTimeListEntry.mTimedFB = this; } void CTimedFB::executeEvent(int pa_nEIID){ switch(pa_nEIID){ case cg_nExternalEventID: sendOutputEvent(csm_nEOID); break; case csm_nEventSTOPID: if(mActive){ getTimer().unregisterTimedFB(this); mActive = false; } break; case csm_nEventSTARTID: if(!mActive){ getTimer().registerTimedFB( &mTimeListEntry, DT()); mActive = true; } break; default: break; } }
转定义到registerTimeFB进行分析
void CTimerHandler::registerTimedFB(STimedFBListEntry *paTimerListEntry, const CIEC_TIME &paTimeInterval) { //calculate the correct interval based on time-base and timer ticks per seconds paTimerListEntry->mInterval = static_cast<TForteUInt32>((paTimeInterval * getTicksPerSecond()) / cgForteTimeBaseUnitsPerSecond); // Correct null intervals that can lead to event queue overflow to at least 1 timer tick if(0 == paTimerListEntry->mInterval) { paTimerListEntry->mInterval = 1; } // set the first next activation time right here to reduce jitter, see Bug #568902 for details paTimerListEntry->mTimeOut = mForteTime + paTimerListEntry->mInterval; { CCriticalRegion criticalRegion(mAddListSync); paTimerListEntry->mNext = mAddFBList; mAddFBList = paTimerListEntry; } }
根据传入的参数registerTimerFB(&mTimeListEntry,DT()),指针指向mTimeListEntry,DT()为我们输入的时间间隔。
paTimerListEntry->mInterval = static_cast<TForteUInt32>((paTimeInterval * getTicksPerSecond()) / cgForteTimeBaseUnitsPerSecond); /*! \brief Get the time base of the runtime * * \return internal runtime ticks per second */ static TForteUInt32 getTicksPerSecond(void){ return cg_nForteTicksPerSecond; }
这里计算了定时块功能的时间间隔,getTicksPersecond()这个函数获取每秒计时器滴答数(返回内部运行时间的每秒刻度数),paTimerInterval* getTicksPersecond(),这一步将传入的时间间隔转化为滴答数,再除以cgForteTimeBaseUnitsPerSecong(这个是Forte中时间单位的单位时间数),进行类型转换赋值给paTimerListEntry->mInterval。
如果传入的时间间隔为0,则将其设置为至少一个计时器滴答数,防止事件队列溢出。
设置下一次触发时间,根据当前时间和计算得到的间隔,计算触发事时间。
paTimerListEntry->mTimeOut = mForteTime+paTimerListEntry->mInterval;