首页 > 代码库 > ecatslv.c及注释

ecatslv.c及注释

<pre name="code" class="cpp">/**
\defgroup ecatslv ecatslv.c: EtherCAT State Machine
\brief Changes to version V5.0:
\brief V5.01 APPL3: Include library demo application
\brief V5.01 ESC2: Add missed value swapping
\brief V5.01 ESM1: Don't overwrite the error reason in case of an failed PS transition
\brief V5.01 ESM2: Don't check the "appl trigger" flag in case on an regular transition to a lower state (OS, SP, PI).
\brief V5.01 ESM3: Call Error acknowledge indication only if error was acknowledged by the master
\brief V5.01 HW3: Update blink code of an SM watchdog error
\brief Changes to version V4.42:
\brief V5.0 ECAT1: Support Explicit Device ID.
\brief V5.0 ECAT2: Application specific functions are moved to application files.
\brief V5.0 ECAT3: Global dummy variables used for dummy ESC operations.
\brief V5.0 ESC1: ESC 32Bit Access added.
\brief V5.0 ESC2: Support ESC EtherCAT LED Indication.
\brief V5.0 ESC3: Support EEPROM Emulation.
\brief V5.0 ESM1: Update "LocalErrorFlag" handling.
\brief V5.0 ESM2: Update Error Acknowledge by ALControl INIT (without error acknowledge)

\brief V5.0 ESM3: Handle pending ESM transition
\brief V5.0 ESM4: ECAT_StateChange() will only be called form application. In case of an communication error AL_ControlInd is called.
\brief V5.0 MBX1: Support configuration without mailbox protocol support.
\brief V5.0 TEST1: Add test application. See Application Note ET9300 for more details.
\brief Changes to version V4.40:\n
\brief V4.42 ESM1: Reset local error flag if master set the acknowledge bit (0x120.4)
\brief Changes to version V4.30:\n
\brief V4.40 ESM5: Enable output SyncManager if local error acknowledged
\brief V4.40 HW0: Use common hardware access functions
\brief V4.40 PDO3: Add support if only input process data is used
\brief V4.40 ECAT4: Add read SM activation register to acknowledge SM Change event
\brief V4.40 PDO2: Check if max process data size was exceed
\brief V4.40 DIAG1: add diagnosis message support
\brief V4.40 ESM4: Change Check WD setup; add define OP_PD_REQUIRED (defines if process data required in state change to OP)
\brief V4.40 WD1: change WD behaviour depending if process data required in OP state
\brief V4.40 MBX4: Change processing order of mailbox SyncManager flags
\brief V4.40 ECAT1: Merge content of HW_Main (spihw.c /mcihw.c) to ECAT_Main
\brief V4.40 ECAT2: Added CheckIfLocalError() to check local flags and set ALStatus /Al Status code if required. This function is called cyclic from MainLoop.
\brief V4.40 ESM2: Add AL_ControlRes() to complete pending state requests. Change SafeOP to OP state response
\brief V4.40 ESM1: Prevent double call of StopOutputHandler()
\brief V4.40 BOOT1: Enable Mailbox SyncManger on state change to BOOT state (to enable FoE)
\brief V4.40 ESM3: Change State machine behaviour according to ETG.1000 V1.0.2 (state change #26)
\brief V4.40 LED1: Set error blink code
\brief V4.40 TIMER1: Added DC_CheckWatchdog() triggered from ECAT_CheckTimer(). Change local Sync0 watchdog variables. Change bus cycle calculation
\brief V4.40 WD1: Change check process data watchdog settings
\brief Changes to version V4.20:\n
\brief V4.30 OBJ 3: initialize the object dictionary in state change INIT->PREOP; clear object dictionary in state change PREOP->INIT
\brief V4.30 SYNC: add 0x1C32:10; 0x1C33:10 (Sync0 cycle), change synchronisation control functionality
\brief V4.30 CiA402: add CiA402_Init() call in state change from PREOP to SAFEOP if DC synchronisation is enabled,
\brief                    else the Init function is called when bus cycle time is calculated [CalcSMCycleTime() ].
\brief                    trigger error handling if the EtherCAT state machine gets a transition from OP to an "lower" state
\brief V4.20 ECAT 1: add LEGACY_MODE behaviour in ECAT_CheckWatchdog()
\brief V4.20 DC 1: Add DC pending state machine handling and Dc watchdog functionality
\brief V4.20 ESM 2: Add State transition from BOOT to INIT
\brief V4.20 ESM 1: Non LEGACY_MODE State change handling
\brief V4.11 Renamed the function parameter "code" of Function "SendSmFailedEmergency() to avoid
\brief problems with some compilers"\n
\brief V4.11 ECAT 1: Fixed a possible problem with state change Init -> SafeOP. The output syncmanager
\brief was enabled by the state change-flag and not by the actual state\n
\brief V4.11 LED 1: Clear the error LED during error acknowledgement\n
\brief V4.11 ESC 1: fixed size of MBXHEADER in the TFOEMBX struct \n
\brief Changes to version V4.08:\n
\brief V4.10 ECAT 1: clear bEcatOutputsReceived in startMailboxhandler()\n
\brief V4.10 ECAT 2: clear bEcatOutputsReceived in stopMailboxhandler()\n
\brief V4.10 ECAT 3: when switching from INIT to BOOT the SM settings shall be checked\n
\brief V4.10 ECAT 4: APPL_StartInputHandler shall always be called and bEcatInputUpdateRunning shall always be set
\brief               in StartInputHandler independent of the input size\n
\brief V4.10 ECAT 5: AL_ControlInd: the error acknowledge behaviour was changed
\brief               according to the protocol enhancements and the conformance test\n
\brief V4.10 ECAT 6: AL_ControlInd: if a state transitions failed the corresponding stop function is
\brief               called to get a consistent set of variables\n
\brief V4.10 ECAT 7: the local application requested to leave the state OP so we have to disable the SM2
\brief                    and make the state change from OP to SAFEOP by calling StopOutputHandler\n
\brief V4.10 ECAT 8: the AL Status Code has to be reset if the error was acknowledged by the master\n
\brief V4.10 ECAT 9: ECAT_StateChange: when waiting for a State Change response from the application the
\brief               AL Status shall only be written if the final state was reached\n
\brief Changes to version V4.07:\n
\brief V4.08 ECAT 1: The watchdog value was not rounded up\n
\brief V4.08 ECAT 2: The value of u16WdValue was not set 0 if the register 0x420 is 0\n
\brief V4.08 ECAT 3: The AlStatusCode is changed as parameter of the function AL_ControlInd\n
\brief V4.08 ECAT 4: In a state transition OP2PREOP, SAFEOP2INIT or OP2INIT is requested,
\brief               this was not working correctly if one of the application functions
\brief               APPL_StopInputHandler or APPL_StopOutputHandler were returning NOERROR_INWORK
\brief               (because only the first state transition was made in that case)\n
\brief V4.08 AOE 1:    AoE was added\n
\brief Changes to version V4.06:\n
\brief V4.07 ECAT 1: The sources for SPI and MCI were merged (in ecat_def.h
\brief                    set the switch MCI_HW to 1 when using the MCI,
\brief                    set the switch SPI_HW to 1 when using the SPI\n
\brief Changes to version V4.00:\n
\brief V4.01 ECAT 1: The Output sync Manager was not disabled when the state OP was left
\brief               by a local request (watchdog or io error)\n
\brief V4.01 ECAT 2: APPL_StopOutputHandler returns an UINT16\n
\brief V4.01 ECAT 3: TwinCAT compatibility mode: The state transition to OP is allowed when the
\brief                     WD-Trigger-Bit of the SM2-Control-Byte (0x814.6) is FALSE, in that case the
\brief                     watchdog will not be started before the outputs were received the first time\n
\brief V4.01 ECAT 4: "else" was too much\n
\brief Changes to version V3.20:\n
\brief V4.00 ECAT 1: The handling of the Sync Manager Parameter was included according to
\brief               the EtherCAT Guidelines and Protocol Enhancements Specification\n
\brief V4.00 ECAT 2: The output sync manager is initialized during the state transition
\brief               from PREOP to SAFEOP that the master can check if the slave could update
\brief               inputs and outputs before switching the slave to OP\n
\brief               behaviour according to the EtherCAT Guidelines and Protocol Enhancements Specification\n
\brief V4.00 ECAT 3: The watchdog will be enabled in SAFE-OP that it can be checked if the last SM event
\brief               was received during the watchdog time before switching to OP\n
\brief V4.00 ECAT 4: The function CheckSmChannelParameters is included in the function
\brief               CheckSmSettings to get a better overview\n
\brief V4.00 ECAT 5: In synchronous mode the slave should support 1- and 3-buffer mode, 3-buffer mode
\brief               should be the standard setting, because the controlling if the process data was updated
\brief               should be done with the TxPDO Toggle, but the 1-buffer mode should be setable too,
\brief               that the master could easily check if all slaves are synchronous by checking the
\brief               the working counter (if the outputs were not read or the inputs were not written
\brief               the ESC of the slave would not increment the working counter with expected value
\brief               if the 1-buffer mode is running)\n
\brief V4.00 ECAT 6: The function ECAT_StateChange was added, which the application should call if a local error
\brief                    is detected (with the parameters alStatus = STATE_SAFEOP, alStatusCode = error code (> 0x1000))
\brief                    or gone (with the parameters alStatus = STATE_OP, alStatusCode = 0)
\brief                    or if one of the functions APPL_StartMailboxHandler, APPL_StopMailboxHandler, APPL_StartInputHandler,
\brief                    APPL_StopInputHandler, APPL_StartOutputHandler, APPL_StopOutputHandler has returned NOERROR_INWORK
\brief                    to acknowledge the last state transition (with the parameters alStatus = new AL-Status, alStatusCode =
\brief                    new AL-Status-Code)\n
\brief V4.00 ECAT 7: The return values for the AL-StatusCode were changed to UINT16\n


\version 5.01
*/

//---------------------------------------------------------------------------------------
/**
\ingroup ecatslv
\file ecatslv.c
\brief Implementation.
*/
//---------------------------------------------------------------------------------------

/*-----------------------------------------------------------------------------------------
------
------    Includes
------
-----------------------------------------------------------------------------------------*/

#define    _ECATSLV_    1
#include "ecatslv.h"
#undef    _ECATSLV_
#define    _ECATSLV_    0

#include "mailbox.h"

#include "ecatcoe.h"
#include "ecatappl.h"

#include "objdef.h"
#include "coeappl.h"

#include "el9800appl.h"

/*--------------------------------------------------------------------------------------
------
------    local Types and Defines
------
--------------------------------------------------------------------------------------*/


/*-----------------------------------------------------------------------------------------
------
------    local variables and constants
------
-----------------------------------------------------------------------------------------*/
UINT16    u16ALEventMask;                      // Value which will be written to the 0x204 register (AL event mask) during the state transition PreOP to SafeOP

/*Dummy variable to trigger read or writes events in the ESC*/
    VARVOLATILE UINT16    u16dummy;

/*-----------------------------------------------------------------------------------------
------
------    local functions
------
-----------------------------------------------------------------------------------------*/


/*-----------------------------------------------------------------------------------------
------
------    functions
------
-----------------------------------------------------------------------------------------*/

/**
\addtogroup ecatslv
@{
*/



/////////////////////////////////////////////////////////////////////////////////////////
/**
 \param  maxChannel    被检查的最后一个SM 
 
 \return                 0: 成功或者返回AL的状态码 
 
 \brief    这个函数检查所有的SM通道 
 

*////////////////////////////////////////////////////////////////////////////////////////

UINT8    CheckSmSettings(UINT8 maxChannel)  
{  
    UINT8 i;  
    UINT8 result = 0;  
    TSYNCMAN ESCMEM *pSyncMan;  
    UINT16 SMLength = 0;  
    UINT16 SMAddress = 0;  
  
    /* 检查接收邮箱的的SM参数(SM0) */  
    pSyncMan = HW_GetSyncMan(MAILBOX_WRITE);  
    SMLength = pSyncMan->Length;  
    SMAddress = pSyncMan->PhysicalStartAddress;  
    if (!(pSyncMan->Settings[SM_SETTING_ACTIVATE_OFFSET] & SM_SETTING_ENABLE_VALUE))  
        /* 接收邮箱不能使能 */  
        result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
    else if ( (pSyncMan->Settings[SM_SETTING_CONTROL_OFFSET] & SM_SETTING_DIRECTION_MASK) != SM_SETTING_DIRECTION_WRITE_VALUE)  
       /* 接收邮箱由主站不能写*/  
        result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
    else if ( (pSyncMan->Settings[SM_SETTING_CONTROL_OFFSET] & SM_SETTING_MODE_MASK) != SM_SETTING_MODE_ONE_BUFFER_VALUE )  
        /* 接收邮箱不是在一个缓存模式 */  
        result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
    else if ( SMLength < MIN_MBX_SIZE )  
        /* 接收邮箱的大小太小 */  
        result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
    else if ( SMLength > MAX_MBX_SIZE )  
        /* 接收邮箱大小太大 */  
        result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
     else if ( SMAddress < MIN_MBX_WRITE_ADDRESS )  
        /* 接收邮箱的地址太小 */  
        result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
    else if ( SMAddress > MAX_MBX_WRITE_ADDRESS)  
        /* 接收邮箱地址太大 */  
        result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
  
    if ( result == 0 )//则说明接收邮箱通过上面的检查  
    {  
        /* 检查发送邮箱的SM参数(SM1) */  
        pSyncMan = HW_GetSyncMan(MAILBOX_READ);  
        SMLength = pSyncMan->Length;  
        SMAddress = pSyncMan->PhysicalStartAddress;  
  
      if (!(pSyncMan->Settings[SM_SETTING_ACTIVATE_OFFSET] & SM_SETTING_ENABLE_VALUE))  
            /* 发送邮箱不使能 */  
            result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
        else if ( (pSyncMan->Settings[SM_SETTING_CONTROL_OFFSET] & SM_SETTING_DIRECTION_MASK) != SM_SETTING_DIRECTION_READ_VALUE)  
           /* 接收邮箱不能被主站读*/  
            result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
        else if ( (pSyncMan->Settings[SM_SETTING_CONTROL_OFFSET] & SM_SETTING_MODE_MASK) != SM_SETTING_MODE_ONE_BUFFER_VALUE )  
            /* 接收邮箱不是一个缓冲区模式 */  
            result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
        else if ( SMLength < MIN_MBX_SIZE )  
            /* 发送邮箱的大小太小 */  
            result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
        else if ( SMLength > MAX_MBX_SIZE )  
            /* 发送邮箱的大小太大 */  
            result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
         else if ( SMAddress < MIN_MBX_READ_ADDRESS )  
            /* 发送邮箱的地址太小 */  
            result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
        else if ( SMAddress > MAX_MBX_READ_ADDRESS )  
            /* 发送邮箱的地址太大 */  
            result = ALSTATUSCODE_INVALIDMBXCFGINPREOP;  
    }  
    if ( result == 0 && maxChannel > PROCESS_DATA_IN )//发送邮箱通过上面的检查  
    {  
        /* 当离开这个函数的时候,b3BufferMode被设置,如果输入和输出运行在3个缓冲区模式 */  
        b3BufferMode = TRUE;  
        /* 检查SM的参数给输入通道(SM的通道3) */  
        pSyncMan = HW_GetSyncMan(PROCESS_DATA_IN);  
    <span style="white-space:pre">  </span>SMLength = pSyncMan->Length;  
    <span style="white-space:pre">  </span>SMAddress = pSyncMan->PhysicalStartAddress;  
  
        if ( (pSyncMan->Settings[SM_SETTING_ACTIVATE_OFFSET] & SM_SETTING_ENABLE_VALUE) != 0 && SMLength == 0 )  
            /* SM3的大小是等于0和SM3是激活的 */  
            result = SYNCMANCHSETTINGS+1;  
        else if (pSyncMan->Settings[SM_SETTING_ACTIVATE_OFFSET] & SM_SETTING_ENABLE_VALUE)  
        {  
            /* SM3是激活的,输入大小是大于0的 */  
            if ( SMLength != nPdInputSize || nPdInputSize == 0 || SMLength > MAX_PD_INPUT_SIZE)  
                /* 大小不想符合sizes don't match */  
                result = SYNCMANCHSIZE+1;  
            else  
                /* 大小相互符合sizes matches */  
            if ( (pSyncMan->Settings[SM_SETTING_CONTROL_OFFSET] & SM_SETTING_DIRECTION_MASK) == SM_SETTING_DIRECTION_READ_VALUE )  
            {  
                /* settings match */  
                if ( ( ( nAlStatus == STATE_PREOP )&&( SMAddress >= MIN_PD_READ_ADDRESS )&&( SMAddress <= MAX_PD_READ_ADDRESS ) )  
                   ||( ( nAlStatus != STATE_PREOP )&&( SMAddress == nEscAddrInputData ) )  
                    )  
                {  
                    /* 地址符合addresses match */  
  
                    if ( (pSyncMan->Settings[SM_SETTING_CONTROL_OFFSET] & SM_SETTING_MODE_MASK) == SM_SETTING_MODE_ONE_BUFFER_VALUE )  
                        /* 如果输入输入运行在1个缓冲区的模式,重置b3BufferMode inputs are running in 1-Buffer-Mode, reset flag b3BufferMode */  
                        b3BufferMode = FALSE;  
                }  
                else  
                    /* 输入地址是超越了允许的范围,或者已经在SAFEOP和OP之间改变input address is out of the allowed area or has changed in SAFEOP or OP */  
                    result = SYNCMANCHADDRESS+1;  
            }  
            else  
                /* 输入设置不相符合input settings do not match */  
                result = SYNCMANCHSETTINGS+1;  
        }  
        else if ( SMLength != 0 || nPdInputSize != 0 )  
            /* 输入大小不等于0,即使SM3的通道是不能使能input size is not zero although the SM3 channel is not enabled */  
            result = SYNCMANCHSIZE+1;  
  
  
        if ( result != 0 )//则出错处理  
        {  
            result = ALSTATUSCODE_INVALIDSMINCFG;  
        }  
    }//结束result==0&&maxChannel...  
  
    if ( result == 0 && maxChannel > PROCESS_DATA_OUT )  
    {  
        /* 检查SM参数给输入(SM2)check the Sync Manager Parameter for the Outputs (Sync Manager Channel 2) */  
        pSyncMan = HW_GetSyncMan(PROCESS_DATA_OUT);  
  
    SMLength = pSyncMan->Length;  
    SMAddress = pSyncMan->PhysicalStartAddress;  
  
    if ( (pSyncMan->Settings[SM_SETTING_ACTIVATE_OFFSET] & SM_SETTING_ENABLE_VALUE) != 0 && SMLength == 0 )  
            /* SM2的大小是等于0或者SM2是使能the SM2 size is 0 and the SM2 is active */  
            result = SYNCMANCHSETTINGS+1;  
        else if (pSyncMan->Settings[SM_SETTING_ACTIVATE_OFFSET] & SM_SETTING_ENABLE_VALUE)  
        {  
            /* 如果SM2的通道是激活的,输出的大小是比0大Sync Manager Channel 2 is active, output size has to greater 0 */  
            if ( SMLength == nPdOutputSize && nPdOutputSize != 0 && SMLength <= ((UINT16)MAX_PD_OUTPUT_SIZE))  
  
            {  
                /* 大小相互符合sizes match */  
                if ( (pSyncMan->Settings[SM_SETTING_CONTROL_OFFSET] & SM_SETTING_DIRECTION_MASK) == SM_SETTING_DIRECTION_WRITE_VALUE )  
                {  
                    /* 设置符合要求settings match */  
                    if ( ( ( nAlStatus == STATE_PREOP )&&( SMAddress >= MIN_PD_WRITE_ADDRESS )&&( SMAddress <= MAX_PD_WRITE_ADDRESS ) )  
                       ||( ( nAlStatus != STATE_PREOP )&&( SMAddress == nEscAddrOutputData ) )  
                        )  
                    {  
                        /* 地址符合addresses match */  
                        {  
                            /* 检查是否看门狗触发使能check, if watchdog trigger is enabled */  
                            if (pSyncMan->Settings[SM_SETTING_CONTROL_OFFSET] & SM_SETTING_WATCHDOG_VALUE)  
                            {  
                                bWdTrigger = TRUE;  
                            }  
                            else  
                            {  
                                bWdTrigger = FALSE;  
                            }  
  
                            if ( (pSyncMan->Settings[SM_SETTING_CONTROL_OFFSET] & SM_SETTING_MODE_MASK) == SM_SETTING_MODE_ONE_BUFFER_VALUE )  
                                /* 输出是运行在1个缓冲区的模式,重置标志位b3BufferMode */  
                                b3BufferMode = FALSE;  
                        }  
                    }  
                    else  
                        /* 输出地址已经超越允许的范围或者在SAFEOP和OP里面转变output address is out of the allowed area or has changed in SAFEOP or OP */  
                        result = SYNCMANCHADDRESS+1;  
                }  
                else  
                    /* 输出设置不相符合output settings do not match */  
                    result = SYNCMANCHSETTINGS+1;  
            }  
            else  
                /* 输出大小不相符合output sizes don't match */  
                result = SYNCMANCHSIZE+1;  
        }  
        else if ( SMLength != 0 || nPdOutputSize != 0 )  
            /* 输出大小不等于0,虽然SM2通道不使能output size is not zero although the SM2 channel is not enabled */  
            result = SYNCMANCHSIZE+1;  
  
  
        if ( result != 0 )//出错状态  
        {  
            result = ALSTATUSCODE_INVALIDSMOUTCFG;  
        }  
    }//对应上面的result==0&&maxChannel...  
  
    if ( result == 0 )  
    {  
        UINT8 SMActivate = 0;  
  
        /* 其它SM通道的使能字节被读来响应SM-改变-中断the Enable-Byte of the rest of the SM channels has to be read to acknowledge the SM-Change-Interrupt */  
        for (i = maxChannel; i < nMaxSyncMan; i++)  
        {  
            pSyncMan = HW_GetSyncMan(i);  
            SMActivate = pSyncMan->Settings[SM_SETTING_ACTIVATE_OFFSET];  
        }  
    }  
    return result;  
}  





/////////////////////////////////////////////////////////////////////////////////////////
/**
 \return    AL Status Code (see ecatslv.h ALSTATUSCODE_....)

 \brief    This function is called in case of the state transition from PREOP to SAFEOP.
 |brief  the areas of the Sync Managers will be checked for overlapping,
 \brief  the synchronization mode (Free Run, Synchron, Distributed Clocks) is selected,
 \brief  the requested cycle time will be checked, the watchdog is started
 \brief  and the AL Event Mask register will be set

*////////////////////////////////////////////////////////////////////////////////////////

UINT16 StartInputHandler(void)
{
    TSYNCMAN ESCMEM * pSyncMan;
    UINT16        dcControl;
    UINT32     cycleTimeSync0 = 0;
    UINT32     cycleTimeSync1 = 0;
    UINT16     wdiv;
    UINT16     wd;
    UINT16    nPdInputBuffer = 3;
    UINT16    nPdOutputBuffer = 3;

    u16ALEventMask = 0;

    bEcatFirstOutputsReceived = FALSE;

    /* get a pointer to the Sync Manager Channel 2 (Outputs) */
    pSyncMan = HW_GetSyncMan(PROCESS_DATA_OUT);
    /* store the address of the Sync Manager Channel 2 (Outputs) */
    nEscAddrOutputData = http://www.mamicode.com/pSyncMan->PhysicalStartAddress;>

ecatslv.c及注释