4 Diac中E_CYCLE模块源码分析

发布时间 2023-08-05 17:29:35作者: 云端听JAY

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;