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 = pSyncMan->PhysicalStartAddress;
    /* get the number of output buffer used for calculating the address areas */
    if ( pSyncMan->Settings[SM_SETTING_CONTROL_OFFSET] & SM_SETTING_MODE_ONE_BUFFER_VALUE )
        nPdOutputBuffer = 1;
    /* get a pointer to the Sync Manager Channel 3 (Inputs) */
    pSyncMan = HW_GetSyncMan(PROCESS_DATA_IN);
    /* store the address of the Sync Manager Channel 3 (Inputs) */
    nEscAddrInputData = pSyncMan->PhysicalStartAddress;

    /* get the number of input buffer used for calculating the address areas */
    if ( pSyncMan->Settings[SM_SETTING_CONTROL_OFFSET] & SM_SETTING_MODE_ONE_BUFFER_VALUE )
        nPdInputBuffer = 1;

    /* it has be checked if the Sync Manager memory areas for Inputs and Outputs will not overlap
       the Sync Manager memory areas for the Mailbox */
    if ( ((nEscAddrInputData + nPdInputSize * nPdInputBuffer) > u16EscAddrSendMbx && (nEscAddrInputData < (u16EscAddrSendMbx + u16SendMbxSize)))
        ||((nEscAddrInputData + nPdInputSize * nPdInputBuffer) > u16EscAddrReceiveMbx && (nEscAddrInputData < (u16EscAddrReceiveMbx + u16ReceiveMbxSize)))
        )
    {
        return ALSTATUSCODE_INVALIDSMINCFG;
    }

    if (
        ((nEscAddrOutputData + nPdOutputSize * nPdOutputBuffer) > u16EscAddrSendMbx && (nEscAddrOutputData < (u16EscAddrSendMbx + u16SendMbxSize)))
        ||((nEscAddrOutputData + nPdOutputSize * nPdOutputBuffer) > u16EscAddrReceiveMbx && (nEscAddrOutputData < (u16EscAddrReceiveMbx + u16ReceiveMbxSize)))
        ||
        ((nEscAddrOutputData + nPdOutputSize * nPdOutputBuffer) > nEscAddrInputData && (nEscAddrOutputData < (nEscAddrInputData + nPdInputSize)))
        )
    {
        /* Sync Manager Channel 2 memory area (Outputs) overlaps the Sync Manager memory areas for the Mailbox
           or the Sync Manager Channel 3 memory area (Inputs) */
        return ALSTATUSCODE_INVALIDSMOUTCFG;
    }

    /* check the DC-Registers */
    /*Read registers 0x980:0x981 (corresponding masks are adapted)*/
    HW_EscReadWord(dcControl, ESC_DC_UNIT_CONTROL_OFFSET);
    dcControl = SWAPWORD(dcControl);

    /* check if Distributed Clocks are enabled */
    if ( dcControl & (ESC_DC_SYNC0_ACTIVE_MASK | ESC_DC_SYNC1_ACTIVE_MASK) )
    {
        /* DC Mode is requested */
        /* Distributed Clocks are enabled, check the correct SYNC0/SYNC1-setting,
           DC_SYNC_ACTIVE is set per default to SYNC0 (in ecatslv.h)
           but this can be overwritten in ecat_def.h */
        if ( dcControl != (ESC_DC_SYNC_UNIT_ACTIVE_MASK | DC_SYNC_ACTIVE) )
        {
            return ALSTATUSCODE_DCINVALIDSYNCCFG;
        }
        else
        {
            /* DC mask for the AL-Event-Mask-Register (0x204)
                DC_EVENT_MASK is set by default to PROCESS_OUTPUT_EVENT
               (optimized DC Cycle in the Synchronization document)
               but this can be overwritten in ecat_def.h */
            u16ALEventMask = DC_EVENT_MASK;
        }

        /* slave is running in DC-mode */
        bDcSyncActive = TRUE;
        // Cycletime for Sync0
        HW_EscReadDWord(cycleTimeSync0, ESC_DC_SYNC0_CYCLETIME_OFFSET);
/* ECATCHANGE_START(V5.01) ESC2*/
        cycleTimeSync0 = SWAPDWORD(cycleTimeSync0);
/* ECATCHANGE_END(V5.01) ESC2*/

        // Cycletime for Sync1
        HW_EscReadDWord(cycleTimeSync1, ESC_DC_SYNC1_CYCLETIME_OFFSET);
/* ECATCHANGE_START(V5.01) ESC2*/
        cycleTimeSync1 = SWAPDWORD(cycleTimeSync1);
/* ECATCHANGE_END(V5.01) ESC2*/
    }
    else
    {
        bDcSyncActive = FALSE;
        /* check entry 0x1C32:01, if free run or synchron synchronization mode is requested */
        if ( sSyncManOutPar.u16SyncType != SYNCTYPE_FREERUN )
        {
            /* ECAT Synchron Mode, the ESC interrupt is enabled */
            bEscIntEnabled = TRUE;
        }
        else
        {
            /* ECAT FreeRun Mode, sync manager has to run in 3-Buffer Mode */
            if ( !b3BufferMode )
                /* 1-Buffer-Mode, refuse the state transition */
                return ALSTATUSCODE_FREERUNNEEDS3BUFFERMODE;
        }
    }

    /* if ECAT Synchron Mode is active and the output size is zero,
       the ESC interrupt will be generated by the PROCESS_INPUT_EVENT */
    if ( bEscIntEnabled && nPdOutputSize == 0 )
    {
        /* Sync Manager Channel 3 event has to activated in the AL-Event mask register */
        u16ALEventMask |= PROCESS_INPUT_EVENT;
    }

    /* check if the requested cycle time exceeds the minimum and maximum values of the cycle time
       (MIN_PDCYCLE_TIME and MAX_PD_CYCLE_TIME are defined in ecat_def.h) */
    if(bDcSyncActive)
    {
        /*bus is synchronised to Sync1 => check if Sync1 cycle time is valid*/
        if(cycleTimeSync1 != 0)
        {
            if (cycleTimeSync1 < MIN_PD_CYCLE_TIME || cycleTimeSync1 > MAX_PD_CYCLE_TIME)
                return ALSTATUSCODE_DCSYNC1CYCLETIME;
        }
        else
        {
            if ( cycleTimeSync0 != 0 && (cycleTimeSync0 < MIN_PD_CYCLE_TIME || cycleTimeSync0 > MAX_PD_CYCLE_TIME) )
                return ALSTATUSCODE_DCSYNC0CYCLETIME;
        }
    }

    /* reset the error counter indicating synchronization problems */
    sCycleDiag.syncFailedCounter = 0;
    /*get the watchdog time (register 0x420). if value is > 0 watchdog is active*/
    HW_EscReadWord(wd, ESC_PD_WD_TIME);
/* ECATCHANGE_START(V5.01) ESC2*/
    wd = SWAPWORD(wd);
/* ECATCHANGE_END(V5.01) ESC2*/
    if (nPdOutputSize > 0 &&  wd != 0 )
    {
    /*get watchdog divider (register 0x400)*/
    HW_EscReadWord(wdiv, ESC_WD_DIVIDER_OFFSET);
/* ECATCHANGE_START(V5.01) ESC2*/
    wdiv = SWAPWORD(wdiv);
/* ECATCHANGE_END(V5.01) ESC2*/
        if ( wdiv != 0 )
        {
            /* the ESC subtracts 2 in register 0x400 so it has to be added here */
            UINT32 d = wdiv+2;

            d *= wd;
            /* store watchdog in ms in variable u16WdValue */
            /* watchdog value has to be rounded up */
            d += 24999;
            d /= 25000;
            EcatWdValue = (UINT16) d;
        }
        else
        {
            wd = 0;
            /* wd value has to be set to zero, if the wd is 0 */
            EcatWdValue = 0;
        }
    }
    else
    {
        /* the watchdog is deactivated or slave has no output process data*/
        wdiv = 0;
        EcatWdValue = 0;
    }

    if((EcatWdValue == 0 && bWdTrigger) || (EcatWdValue != 0 && !bWdTrigger))
    {
        /* if the WD-Trigger in the Sync Manager Channel 2 Control-Byte is set (Bit 6 of Register 0x814)
            an error has to be returned */
        return ALSTATUSCODE_INVALIDWDCFG;
    }

    if ( bEscIntEnabled && nPdOutputSize != 0 )
    {
        /* ECAT synchron Mode is active, the Sync Manager Channel 2 event
           has to activated in the AL-Event mask register */
        u16ALEventMask |= PROCESS_OUTPUT_EVENT;
    }
/*The application ESM function is separated from this function to handle pending transitions*/

    Sync0WdValue = 0;
    Sync0WdCounter = 0;
    bDcRunning = FALSE;
    bSmSyncToggle = FALSE;
    bPllRunning = FALSE;
    i16WaitForPllRunningTimeout = 0;
    sSyncManInPar.u16SyncError = 0;
    sSyncManOutPar.u16SyncError = 0;
    sSyncManOutPar.u32SmEventMissedCounter = 0;

    /* update the entries 0x1C32:01 and 0x1C33:01 */
    if ( bDcSyncActive )
    {
        /*calculate the Sync0 Watchdog counter value the minimum value is 1 ms
            if the sync0 cycle is greater 500us the Sync0 Wd value is 2*Sycn0 cycle */
        if(cycleTimeSync0 == 0)
        {
            Sync0WdValue = 0;
        }
        else
        {
            UINT32 Sync0Cycle = cycleTimeSync0/100000;
            if(Sync0Cycle < 5)
            {
                /*Sync0 cycle less than 500us*/
                Sync0WdValue = 1;
            }
            else
            {
                Sync0WdValue = (Sync0Cycle*2)/10;
            }
        }
        if(cycleTimeSync1 != 0)
        {
            /*the applications synchronised to Sync1*/
            sSyncManOutPar.u32Sync0CycleTime = cycleTimeSync0;
            sSyncManInPar.u32Sync0CycleTime = cycleTimeSync0;

            sSyncManOutPar.u32CycleTime = cycleTimeSync1;
            sSyncManInPar.u32CycleTime = cycleTimeSync1;

            sSyncManOutPar.u16SyncType = SYNCTYPE_DCSYNC1;
            sSyncManInPar.u16SyncType = SYNCTYPE_DCSYNC1;

        }
        else
        {
            sSyncManOutPar.u32CycleTime = cycleTimeSync0;
            sSyncManInPar.u32CycleTime = cycleTimeSync0;

            /*the bus is synchronised with Sync0*/
            sSyncManOutPar.u16SyncType = SYNCTYPE_DCSYNC0;
            sSyncManInPar.u16SyncType = SYNCTYPE_DCSYNC0;
        }
    }
    else

    if ( bEscIntEnabled )
    {
        /* ECAT Synchron Mode */
        sSyncManOutPar.u16SyncType = SYNCTYPE_SYNCHRON;
        sSyncManInPar.u16SyncType = SYNCTYPE_SM2INT;
        /*Trigger bus cycle calculation*/
        sSyncManOutPar.u16GetCycleTime = 1;
    }
    else
    {
        /* ECAT FreeRun Mode */
        sSyncManOutPar.u16SyncType = SYNCTYPE_FREERUN;
        sSyncManInPar.u16SyncType = SYNCTYPE_FREERUN;
    }
/*CiA specific code is moved to CiA402 ESM functions*/
    if(nPdOutputSize > 0)
    {
        HW_EnableSyncManChannel(PROCESS_DATA_OUT);
    }

    if(nPdInputSize > 0)
    {
        HW_EnableSyncManChannel(PROCESS_DATA_IN);
    }

    /*write initial input data*/
    PDO_InputMapping();

    return ALSTATUSCODE_NOERROR;
}

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

 \brief    This function is called in case of the state transition from SAFEOP to OP.
 \brief  It will be checked if outputs had to be received before switching to OP
 \brief  and the state transition would be refused if outputs are missing

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

UINT16 StartOutputHandler(void)
{
    UINT16 result = ALSTATUSCODE_NOERROR;
    if(bLocalErrorFlag)
    {
        /*Local error still exists => skip state request to OP and response with "u16LocalErrorCode"*/
        return u16LocalErrorCode;
    }
/*The application ESM function is separated from this function to handle pending transitions*/

    /*DC synchronisation is active wait until pll is valid*/
    if(bDcSyncActive)
    {
        i16WaitForPllRunningTimeout = 200;
        i16WaitForPllRunningCnt = 0;
        result = NOERROR_INWORK;
    }

    return result;
}

/////////////////////////////////////////////////////////////////////////////////////////
/**
 \brief    This function is called in case of the state transition from OP to SAFEOP
 \brief  the outputs can be set to an application specific safe state,
 \brief  the state transition can be delayed by returning NOERROR_INWORK

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

void StopOutputHandler(void)
{
    /* reset the flags that outputs were received and that the slave is in OP */
    bEcatFirstOutputsReceived = FALSE;
     bEcatOutputUpdateRunning = FALSE;

/*The application ESM function is separated from this function to handle pending transitions*/
}

/////////////////////////////////////////////////////////////////////////////////////////
/**
  \brief    This function is called in case of the state transition from SAFEOP to PREOP

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

void StopInputHandler(void)
{
    if(nPdOutputSize > 0)
    {
        /* disable the Sync Manager Channel 2 (outputs) */
        HW_DisableSyncManChannel(PROCESS_DATA_OUT);
    }

    if(nPdInputSize > 0)
    {
        /*disable Sync Manager 3 (inputs) if no outputs available*/
        HW_DisableSyncManChannel(PROCESS_DATA_IN);
    }

    /* reset the events in the AL Event mask register (0x204) */
    HW_ResetALEventMask( ~(SYNC0_EVENT | SYNC1_EVENT | PROCESS_INPUT_EVENT | PROCESS_OUTPUT_EVENT) );
    /* reset the flags */
    bEcatFirstOutputsReceived = FALSE;
    bEscIntEnabled = FALSE;
/*The application ESM function is separated from this function to handle pending transitions*/

    bDcSyncActive = FALSE;
    bDcRunning = FALSE;
    bPllRunning = FALSE;
    bSmSyncToggle = FALSE;

    i16WaitForPllRunningTimeout = 0;

    bWdTrigger = FALSE;
    bEcatInputUpdateRunning = FALSE;
}

/////////////////////////////////////////////////////////////////////////////////////////
/**
 \param alStatus        New AL Status (written to register 0x130)
 \param alStatusCode    New AL Status Code (written to register 0x134)

  \brief  The function changes the state of the EtherCAT ASIC to the requested.
*////////////////////////////////////////////////////////////////////////////////////////
void SetALStatus(UINT8 alStatus, UINT16 alStatusCode)
{
    UINT16 Value = alStatusCode;

    /*update global status variable if required*/
    if(nAlStatus != alStatus)        //全局变量nAlStatus的状态值更新
    {
        nAlStatus = alStatus;
    }

    if (alStatusCode != 0xFFFF)      //如果AL状态不为0XFFFF
    {
        Value = SWAPWORD(Value);

        HW_EscWriteWord(Value,ESC_AL_STATUS_CODE_OFFSET);  //对地址0X134写数据,更新应用层状态码
    }

    Value = nAlStatus;    //0X0001
    Value = SWAPWORD(Value);    //交换高低8位,原因,写函数先写高8位,后写低8位
    HW_EscWriteWord(Value,ESC_AL_STATUS_OFFSET);  //对地址0X130写数据  先写0X130,后写0X131

    /*The Run LED state is set in Set LED Indication, only the Error LED blink code is set here,在此只设置故障显示led */

    /*set Error blink code*/  //AL状态错误下的外设设置情况
    if(alStatusCode == 0x00 || !(alStatus & STATE_CHANGE))
    {
        u8EcatErrorLed = LED_OFF;           //无状态或无状态切换,正确则灯暗
    }
    else if((alStatusCode == ALSTATUSCODE_NOSYNCERROR) ||
        (alStatusCode == ALSTATUSCODE_DCPLLSYNCERROR))
    {
        u8EcatErrorLed = LED_SINGLEFLASH;// 单闪烁
    }
    else if((alStatusCode == ALSTATUSCODE_SMWATCHDOG))
    {
/* ECATCHANGE_START(V5.01) HW3*/
        u8EcatErrorLed = LED_DOUBLEFLASH; //双闪烁
/* ECATCHANGE_END(V5.01) HW3*/
    }
    else
    {
        u8EcatErrorLed = LED_BLINKING;   //单闪灯亮
    }
}

/////////////////////////////////////////////////////////////////////////////////////////
/**
 \param    alControl        请求的新的状态
 \param alStatusCode    请求的状态码 

 \brief    这个函数处理EtherCAT状态机。它被调用
            * 在AL控制时间发生(0x220的位0)触发,当主站写AL控制寄存器,其中alControl包含AL控制的内容(0x120)的时候
            * 当SM改变事件(0x220)的第4位,当激活SYNCM y寄存器被主站写(从Ecat_Main函数),alControl包含实际的状态在(0x130)的位0到3
            * 防止本地的看门狗溢出(从ECAT_Main函数),alControl包含一个新的请求的状态(SAFE_OP状态)的时候
            *防止应用程序特殊的事件来改变EtherCAT的状态(从应用程序),alControl包含新的请求状态(INIT,PRE_OP和SAFE_OP状态)的时候  

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

void AL_ControlInd(UINT8 alControl, UINT16 alStatusCode)
{
    UINT16        result = 0;
    UINT8            bErrAck = 0;
    UINT8         stateTrans;
    /*deactivate ESM timeout counter*/
    EsmTimeoutCounter = -1;
    bApplEsmPending = TRUE;

     /* 为了能被主站响应,重置错误标号 */
    if ( alControl & STATE_CHANGE )
    {
        bErrAck = 1;
        nAlStatus &= ~STATE_CHANGE;
        /*使能SM2,SM2被移到状态转换块。首先检查SM的设置.*/
    }
    else if ( (nAlStatus & STATE_CHANGE)
    // HBu 17.04.08: the error has to be acknowledged before when sending the same (or a higher) state
    //               (the error was acknowledged with the same state before independent of the acknowledge flag)
    /*Error Acknowledge with 0xX1 is allowed*/
           && (alControl & STATE_MASK) != STATE_INIT )
        /* the error flag (Bit 4) is set in the AL-Status and the ErrAck bit (Bit 4)
           is not set in the AL-Control, so the state cannot be set to a higher state
           and the new state request will be ignored */
        return;
    else
    {
        nAlStatus &= STATE_MASK;
    }

    /* 产生一个变量给状态转换(位0-3:新的状态(AL控制),位4-7:旧的状态) */
    alControl &= STATE_MASK;
    stateTrans = nAlStatus;
    stateTrans <<= 4;
    stateTrans += alControl;

    /* 根据状态转换,检查SYNCM的设置check the SYNCM settings depending on the state transition */
    switch ( stateTrans )
    {
    case INIT_2_PREOP:
    case OP_2_PREOP:
    case SAFEOP_2_PREOP:
    case PREOP_2_PREOP:
             /* 在预运行状态(PREOP),只有SYNCM给SYNCM0和SYNCM1(邮箱)的设置被检查,只要结果不等于0,
			 从站将会停留或者转换到INIT状态和设置AL-Status的ErrorInd 位(位4) */
        result = CheckSmSettings(MAILBOX_READ+1);
        break;
    case PREOP_2_SAFEOP:
        /* 在检查SYNCM的设置给SYNCM2和SYNCM3(过程数据)之前,
		需要的输入数据(nPdInputSize)和输出数据(nPdOutputSize)的长度可以被改变(通过PDO-Assign和PDO-Mapping)。
		如果检查结果不等于0,从站将会停留在PREOP和设置AL-状态的错误位(位4) */  

        result = APPL_GenerateMapping(&nPdInputSize,&nPdOutputSize);
        if (result != 0)
            break;
    case SAFEOP_2_OP:
    case OP_2_SAFEOP:
    case SAFEOP_2_SAFEOP:
    case OP_2_OP:
		 /* 在安全运行(SAFEOP)和运行(OP)阶段,
		 SYNCM设置给所有的SYNCM将被检查,
		 如果检查结果不等于0,从站将会停留或者转换到PREOP和设置AL-Status的错误位(位4) */
         result = CheckSmSettings(nMaxSyncMan);
        break;
    }

    if ( result == 0 )
    {
      /* 如果result的结果等于0,将会执行对应的本地处理服务根据状态的转换execute the corresponding local management service(s) depending on the state transition */
        nEcatStateTrans = 0;
        switch ( stateTrans )
        {
        case INIT_2_BOOT    :
            result = ALSTATUSCODE_BOOTNOTSUPP;
            break;

        case BOOT_2_INIT    :
            result = ALSTATUSCODE_BOOTNOTSUPP;
            break;
        case INIT_2_PREOP :
            {
             /*在mailbox.c里面的函数MBX_StartMailboxHandler函数,
			 检查是否邮箱SM区域SM0和SM1是否存在相互的重叠?
			 如果结果是不等于0,则从站将停留在INIT状态和设置AL-Status的错误位(位4 */  

            result = MBX_StartMailboxHandler();
            if (result == 0)
            {
                bApplEsmPending = FALSE;
                /* 此外,这里有一个另外得应用程序特别的检查(在ecatappl.c)如果状态在INIT到PREOP被转换,如果结果不等于0,从站将停留在INIT和设置AL-Status的错误代码(位4)additionally there could be an application specific check (in ecatappl.c)
                   if the state transition from INIT to PREOP should be done
                 if result is unequal 0, the slave will stay in INIT
                 and sets the ErrorInd Bit (bit 4) of the AL-Status */
                result = APPL_StartMailboxHandler();
                if ( result == 0 )
                {
                    bMbxRunning = TRUE;
                }
            }

            if(result != 0 && result != NOERROR_INWORK)
            {
              /*停止APPL邮箱操作,如果APPL开始邮箱操作在之前被调用
			  Stop APPL Mbx handler if APPL Start Mbx handler was called before*/
                   if(!bApplEsmPending)
                    APPL_StopMailboxHandler();

                 MBX_StopMailboxHandler();
            }

            }
            break;

        case PREOP_2_SAFEOP:
             /* 开始输入操作(函数在上面被定义)start the input handler (function is defined above) */  

            result = StartInputHandler();
            if ( result == 0 )
            {
                bApplEsmPending = FALSE;
                result = APPL_StartInputHandler(&u16ALEventMask);

                if(result == 0)
                {
                    /* initialize the AL Event Mask register (0x204) */
                    HW_SetALEventMask( u16ALEventMask );

                    bEcatInputUpdateRunning = TRUE;
                }
            }

           /*如果一个开始输入操作,返回一个错误,停止输入操作if one start input handler returned an error stop the input handler*/  

            if(result != 0 && result != NOERROR_INWORK)
            {
                if(!bApplEsmPending)
                {
                     /*之前,APPL开始操作被调用,调用APPL停止操作Call only the APPL stop handler if the APPL start handler was called before*/
                    /*应用程序可以响应状态转换在函数APPL_StopInputHandle这个函数The application can react to the state transition in the function APPL_StopInputHandler */
/*ECATCHANGE_START(V5.01) ESM1*/
                    APPL_StopInputHandler();
/*ECATCHANGE_END(V5.01) ESM1*/
                }

                StopInputHandler();
            }
            break;

        case SAFEOP_2_OP:
           /* 开始输出操作(函数在上面被定义)start the output handler (function is defined above) */
              result = StartOutputHandler();
            if(result == 0)
            {
                bApplEsmPending = FALSE;
                result = APPL_StartOutputHandler();

                if(result == 0)
                {
                       /*设备是在运行状态Device is in OPERATINAL*/
                   bEcatOutputUpdateRunning = TRUE;
                }

            }

            if ( result != 0 && result != NOERROR_INWORK)
            {
                if(!bApplEsmPending)
                    APPL_StopOutputHandler();

                StopOutputHandler();
            }

            break;

        case OP_2_SAFEOP:
            //* 停止输出操作(函数在上面定义)stop the output handler (function is defined above) */
/* ECATCHANGE_START(V5.01) ESM2*/
            APPL_StopOutputHandler();
/* ECATCHANGE_END(V5.01) ESM2*/

            StopOutputHandler();
            break;

        case OP_2_PREOP:
          /* 停止输出操作(函数在上面定义)stop the output handler (function is defined above) */
/* ECATCHANGE_START(V5.01) ESM2*/
            result = APPL_StopOutputHandler();
/* ECATCHANGE_END(V5.01) ESM2*/

            StopOutputHandler();

            if (result != 0)
                break;

            stateTrans = SAFEOP_2_PREOP;

        case SAFEOP_2_PREOP:
             /* 停止输出操作(函数在上面定义)stop the input handler (function is defined above) */
/* ECATCHANGE_START(V5.01) ESM2*/
            APPL_StopInputHandler();
/* ECATCHANGE_END(V5.01) ESM2*/

            StopInputHandler();
            break;

        case OP_2_INIT:
            /* stop the output handler (function is defined above) */
/* ECATCHANGE_START(V5.01) ESM2*/
            result = APPL_StopOutputHandler();
/* ECATCHANGE_END(V5.01) ESM2*/

            StopOutputHandler();
            if (result != 0)
                break;

            stateTrans = SAFEOP_2_INIT;

        case SAFEOP_2_INIT:
            /* stop the input handler (function is defined above) */
/* ECATCHANGE_START(V5.01) ESM2*/
            result = APPL_StopInputHandler();
/* ECATCHANGE_END(V5.01) ESM2*/

            StopInputHandler();
            if (result != 0)
                break;
            stateTrans = PREOP_2_INIT;

        case PREOP_2_INIT:
            MBX_StopMailboxHandler();
            result = APPL_StopMailboxHandler();
            break;

        case INIT_2_INIT:
        case PREOP_2_PREOP:
        case SAFEOP_2_SAFEOP:
        case OP_2_OP:
/*ECATCHANGE_START(V5.01) ESM3*/
            if(bErrAck)
                APPL_AckErrorInd(stateTrans);
/*ECATCHANGE_END(V5.01) ESM3*/

            if(!bLocalErrorFlag)
            {
                /*没有本地错误标号,使能SMno local error flag is currently active, enable SM*/
               if ( nAlStatus & (STATE_SAFEOP | STATE_OP))
                {
                    if(nPdOutputSize > 0)
                    {
                        HW_EnableSyncManChannel(PROCESS_DATA_OUT);
                    }
                    else
                    {
                        HW_EnableSyncManChannel(PROCESS_DATA_IN);
                    }
                }
            }
            result = NOERROR_NOSTATECHANGE;
            break;

        case INIT_2_SAFEOP:
        case INIT_2_OP:
        case PREOP_2_OP:
        case PREOP_2_BOOT:
        case SAFEOP_2_BOOT:
        case OP_2_BOOT:
            result = ALSTATUSCODE_INVALIDALCONTROL;
            break;

        default:
            result = ALSTATUSCODE_UNKNOWNALCONTROL;
            break;
        }
    }
    else
    {
       /* 检查SM设置不成功,转换回到PREOP和INIT状态the checking of the sync manager settings was not successful
            switch back the state to PREOP or INIT */
        switch (nAlStatus)
        {
        case STATE_OP:
            /* 停止输出操作(函数在上面定义)stop the output handler (function is defined above) */
/* ECATCHANGE_START(V5.01) ESM2*/
            APPL_StopOutputHandler();
/* ECATCHANGE_END(V5.01) ESM2*/
            StopOutputHandler();
        case STATE_SAFEOP:
            /* stop the input handler (function is defined above) */
/* ECATCHANGE_END(V5.01) ESM2*/
            APPL_StopInputHandler();
/* ECATCHANGE_END(V5.01) ESM2*/

            StopInputHandler();

        case STATE_SAFEOP:
            /* 停止输入操作(函数在上面定义)stop the input handler (function is defined above) */
/* ECATCHANGE_END(V5.01) ESM2*/
            APPL_StopInputHandler();
/* ECATCHANGE_END(V5.01) ESM2*/  

            StopInputHandler();  

        case STATE_PREOP:  

            if ( result == ALSTATUSCODE_INVALIDMBXCFGINPREOP )
            {
#if MAILBOX_SUPPORTED
                /* 邮箱的SM设置是错误的,转换回到INIT状态the mailbox sync manager settings were wrong, switch back to INIT */
                MBX_StopMailboxHandler();
                APPL_StopMailboxHandler();
#else
            /*禁止SM0Disable SM0 (邮箱输出)*/
            HW_DisableSyncManChannel(MAILBOX_WRITE);  

            /*禁止 SM1 (邮箱输入)*/
            HW_DisableSyncManChannel(MAILBOX_READ);
#endif  

                nAlStatus = STATE_INIT;
            }
            else
                nAlStatus = STATE_PREOP;
        }
    }  

    if ( result == NOERROR_INWORK )
    {
        /* 状态转换仍然在工作,ECAT_SrateChange需要被调用从应用程序里面state transition is still in work
            ECAT_StateChange must be called from the application */
        bEcatWaitForAlControlRes = TRUE;
        /* 状态转换需要被存储state transition has to be stored */
        nEcatStateTrans = stateTrans;  

        /*初始化ESM的超时计数(将被递减由本地的定时器,定时1ms的时间)Init ESM timeout counter (will be decremented with the local 1ms timer)*/
        switch(nEcatStateTrans)
        {
            case INIT_2_PREOP:
            case INIT_2_BOOT:
                EsmTimeoutCounter = PREOPTIMEOUT;
            break;
            case PREOP_2_SAFEOP:
            case SAFEOP_2_OP:
                EsmTimeoutCounter = SAFEOP2OPTIMEOUT;
                break;
           default:
                EsmTimeoutCounter = 200; //设置常规的超时值为200msSet default timeout value to 200ms
                break;
        }
        EsmTimeoutCounter -= 50; //减去50ms从超时到响应,在主站进入超时之前subtract 50ms from the timeout to react before the master runs into a timeout.  

    }
    else
    /* AL状态代码寄存器不应该被更改,如果函数被调用,如果SM转变时间或者同个状态的AL控制事件The AL Status Code register shall not be modified if the function is called
       in case of SM change event or an AL-Control event with the same state */
    if ( alControl != (nAlStatus & STATE_MASK) )
    {
        if ( (result != 0 || alStatusCode != 0) && ((alControl | nAlStatus) & STATE_OP) )
        {
            /* 本地的应用程序需要请求离开状态OP,所以,我们需要禁止SM2和使状态转换从op到SAFEOP同个调用函数StopOutputHandler()the local application requested to leave the state OP so we have to disable the SM2
               and make the state change from OP to SAFEOP by calling StopOutputHandler */  

            //如果输出更新仍然进行,需要执行StopOutputHandler()函数only execute StopOutputHandler() if Output update is still running
            if(bEcatOutputUpdateRunning)
            {
/* ECATCHANGE_START(V5.01) ESM2*/
                APPL_StopOutputHandler();
/* ECATCHANGE_END(V5.01) ESM2*/  

                StopOutputHandler();
            }  

            if(nPdOutputSize > 0)
            {
                /* 禁止Sync Manager通道2(输出)disable the Sync Manager Channel 2 (outputs) */
                HW_DisableSyncManChannel(PROCESS_DATA_OUT);
            }
            else
            {
                /*禁止Sync Manager3(输入),如果没有输入变量disable Sync Manager 3 (inputs) if no outputs available*/
                HW_DisableSyncManChannel(PROCESS_DATA_IN);
            }  

        }
        if ( result != 0 )
        {
            if ( nAlStatus == STATE_OP )
                nAlStatus = STATE_SAFEOP;
            /* 保持失败的状态,如果AL状态代码应该被重置,如果一个成功的转换发生save the failed status to be able to decide, if the AL Status Code shall be
               reset in case of a coming successful state transition */
            nAlStatus |= STATE_CHANGE;
        }
        else
        {
            /* 状态转换成功state transition was successful */
            if ( alStatusCode != 0 )
            {
                /* 来自用户的状态转换请求state change request from the user */
                result = alStatusCode;
                alControl |= STATE_CHANGE;
            }
            /* 响应新的状态转换acknowledge the new state */
            nAlStatus = alControl;
        }  

        bEcatWaitForAlControlRes = FALSE;  

        /* 写用户状态寄存器write the AL Status register */
        SetALStatus(nAlStatus, result);
    }
    else
    {
         bEcatWaitForAlControlRes = FALSE;  

        /* AL-Status应该被更新和AL-Status-Code应该被重置,如果错误码被响应AL-Status has to be updated and AL-Status-Code has to be reset
           if the the error bit was acknowledged */
        SetALStatus(nAlStatus, 0);
    }
#if CiA402_DEVICE
    if((stateTrans & 0x80) && !(stateTrans & STATE_OP))    //状态转换从运行状态到非运行状态state transition from OP to "not OP"
    {
        CiA402_LocalError(ERROR_COMMUNICATION);
    }
#endif  

}  

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

 \brief    This function is called cyclic if a state transition is pending (bEcatWaitForAlControlRes == TRUE)
 \brief    If the ESM timeout is expired the state transition will be rejected. Otherwise the application specific state transition function is called.
 \brief    If the pending state transition is triggered by the application the transition need to be completed by the application (ECAT_StateChange())
  *////////////////////////////////////////////////////////////////////////////////////////
void AL_ControlRes(void)
{
    if(bEcatWaitForAlControlRes)
    {
        UINT16 result = 0;
        UINT8 Status = 0;
        UINT16 StatusCode = 0;

        if(EsmTimeoutCounter == 0)
        {
            Status =  (UINT8)(nEcatStateTrans >> 4);

            /* ESM timeout expired*/
            switch(nEcatStateTrans)
            {
                case INIT_2_PREOP:
                case INIT_2_BOOT:

                    if(!bApplEsmPending)
                        APPL_StopMailboxHandler();

                    MBX_StopMailboxHandler();
                    if(bLocalErrorFlag)
                    {
                        /*Set application specified error*/
                        StatusCode = u16LocalErrorCode;
                    }
                    else
                    {
                        /*Set unspecified error*/
                        StatusCode = ALSTATUSCODE_UNSPECIFIEDERROR;
                    }
                break;
                case PREOP_2_SAFEOP:
                    if(!bApplEsmPending)
                        APPL_StopInputHandler();

                    StopInputHandler();

                    if(bLocalErrorFlag)
                    {
                        /*Set application specified error*/
                        StatusCode = u16LocalErrorCode;
                    }
                    else
                    {
                        /*Set unspecified error*/
                        StatusCode = ALSTATUSCODE_UNSPECIFIEDERROR;
                    }
                break;
                case SAFEOP_2_OP:
                    if(bDcSyncActive)
                    {
                        /*SafeOP to OP timeout expired check which AL status code need to be written*/
                        if(!bDcRunning)
                        {
                            /*no Sync0 signal received*/
                            StatusCode = ALSTATUSCODE_NOSYNCERROR;
                        }
                        else if(!bEcatFirstOutputsReceived)
                        {
                            /*no process data received*/
                            StatusCode = ALSTATUSCODE_SMWATCHDOG;
                        }
                        else
                        {
                            /*Pll is not valid*/
                            StatusCode = ALSTATUSCODE_DCPLLSYNCERROR;
                        }
                    }
                    else
                    {
                        StatusCode = ALSTATUSCODE_SMWATCHDOG;
                    }

                    /*Stop handler on failed transition*/
                    if(StatusCode != 0)
                    {
                        if(!bApplEsmPending)
                            APPL_StopOutputHandler();

                        StopOutputHandler();
                    }
                break;
            }
        } //ESM timeout
        else
        {
            /*Call application specific transition function and complete transition it the function returns 0*/
            switch(nEcatStateTrans)
            {
                case INIT_2_PREOP:
                case INIT_2_BOOT:
                    if(bApplEsmPending)
                    {
                        bApplEsmPending = FALSE;
                        /*APPL_StartMailboxHandler() need to be called*/
                        result = APPL_StartMailboxHandler();

                        if(result == 0)
                        {
                            /*The application specific transition was successful => set active mailbox handler indication*/
                            bMbxRunning = TRUE;
                            Status =  (UINT8)(nEcatStateTrans & STATE_MASK);
                        }
                        else
                        {
                            /*The application specific transition failed.
                            (In pending case the application need to complete the transition)*/

                            if(result != NOERROR_INWORK)
                            {
                                APPL_StopMailboxHandler();
                                MBX_StopMailboxHandler();
                            }
                        }
                    }
                break;
                case PREOP_2_SAFEOP:
                    if(bApplEsmPending)
                    {
                        bApplEsmPending = FALSE;
                        result = APPL_StartInputHandler(&u16ALEventMask);

                        if(result == 0)
                        {
                            bEcatInputUpdateRunning = TRUE;
                            Status = STATE_SAFEOP;
                        }
                        else
                        {
                            /*The application specific transition failed.
                            (In pending case the application need to complete the transition)*/

                            if(result != NOERROR_INWORK)
                            {
                                APPL_StopInputHandler();
                                StopInputHandler();
                            }
                        }
                    }
                break;
                case SAFEOP_2_OP:
                   if(bApplEsmPending)
                    {
                        if(bDcSyncActive)
                        {
                            if(i16WaitForPllRunningTimeout > 0 && i16WaitForPllRunningTimeout <= i16WaitForPllRunningCnt)
                            {
                                /*Pll sequence valid for 200ms (set in APPL_StartOutputHandler() )
                                acknowledge state transition to OP */

                                i16WaitForPllRunningTimeout = 0;
                                i16WaitForPllRunningCnt = 0;

                                result = APPL_StartOutputHandler();

                                if(result == 0)
                                {
                                    /* Slave is OPERATIONAL */
                                    bEcatOutputUpdateRunning = TRUE;
                                    Status = STATE_OP;
                                }
                                else
                                {
                                    if(result != NOERROR_INWORK)
                                    {
                                        APPL_StopOutputHandler();
                                        StopOutputHandler();
                                    }
                                }
                            }
                        }
                        else
                        {
                            if(nPdOutputSize == 0 || bEcatFirstOutputsReceived)
                            {
                                result = APPL_StartOutputHandler();

                                if(result == 0)
                                {
                                    /* Slave is OPERATIONAL */
                                    bEcatOutputUpdateRunning = TRUE;
                                    Status = STATE_OP;
                                }
                                else
                                {
                                    if(result != NOERROR_INWORK)
                                    {
                                        APPL_StopOutputHandler();
                                        StopOutputHandler();
                                    }
                                }
                            }
                        }
                    }
                break;
            }//Switch - transition
        }

        if(Status != 0)
        {
            /*Pending state transition finished => write AL Status and AL Status Code*/
            bEcatWaitForAlControlRes = FALSE;

            if(StatusCode != 0)
                Status |= STATE_CHANGE;

            SetALStatus(Status,StatusCode);
        }
    }// Pending state transition (bEcatWaitForAlControlRes == true)
}

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

 \brief    This function checks the current Sync state and set the local flags        //该函数主要是检测当前的同步状态,并设置标志位
 The analyse of the local flags is handled in "CheckIfEcatError"                        //当ECAT错误时,检测该标志位

*////////////////////////////////////////////////////////////////////////////////////////
void DC_CheckWatchdog(void)                               //每1ms执行一次计数
{
    if(bDcSyncActive)                                            //如果分布时钟同步使能,bDcSyncActive为使能标志位
    {
        /*Check the Sync0 cycle if Sync0 Wd is enabled*/
        if(Sync0WdValue > 0)
        {
            Sync0WdCounter ++;
            if(Sync0WdCounter > Sync0WdValue)
            {
                /*Sync0 watchdog expired*/
                bDcRunning = FALSE;                              //看门狗同步越限
            }
        }

        if(bDcRunning)
        {
           if(sSyncManOutPar.u32SmEventMissedCounter < sErrorSettings.u32SyncErrorCounterLimit)
            {
                bPllRunning = TRUE;

                /*Wait for PLL is active increment the Pll valid counter*/
                if(i16WaitForPllRunningTimeout > 0)
                {
                    i16WaitForPllRunningCnt++;
                }
            }
            else
            {
                bPllRunning = FALSE;
                sSyncManOutPar.u16SyncError = 1;

                /*Wait for PLL is active reset the Pll valid counter*/
                if(i16WaitForPllRunningTimeout > 0)
                {
                    i16WaitForPllRunningCnt = 0;
                }
            }
        }
        else
        {
            bPllRunning = FALSE;
        }
    }
}

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

 \brief    Checks communication and synchronisation variables and update AL status / AL status code if an error has occurred
 检查通信和同步,如果发生了一个错误则更新AL状态/AL状态码

*////////////////////////////////////////////////////////////////////////////////////////
void CheckIfEcatError(void)
{
if(bDcSyncActive)
{
    if(bEcatOutputUpdateRunning)
    {
        /*Slave is in OP state*/
        if(!bDcRunning)
        {
            AL_ControlInd(STATE_SAFEOP, ALSTATUSCODE_FATALSYNCERROR);
            return;
        }
        else if(!bPllRunning)
        {
            AL_ControlInd(STATE_SAFEOP, ALSTATUSCODE_DCPLLSYNCERROR);
            return;
        }

    }
}

        /*if the watchdog is enabled check the the process data watchdog in the ESC
        and set the AL status code 0x1B if the watchdog expired*/
        if ( EcatWdValue != 0 )
        {
            /*watchdog time is set => watchdog is active*/
            UINT16 WdStatusOK = 0;

            HW_EscReadWord(WdStatusOK,ESC_PD_WD_STATE);
/* ECATCHANGE_START(V5.01) ESC2*/
            WdStatusOK = SWAPWORD(WdStatusOK);
/* ECATCHANGE_END(V5.01) ESC2*/
            if(!(WdStatusOK & ESC_PD_WD_TRIGGER_MASK))
            {
                /*The device is in OP state*/

                if(bEcatOutputUpdateRunning
                )
                {
                    AL_ControlInd(STATE_SAFEOP,ALSTATUSCODE_SMWATCHDOG);
                    return;
                }
                else
                {
                    bEcatFirstOutputsReceived = FALSE;
                }
            }
        }

}
/////////////////////////////////////////////////////////////////////////////////////////
/**
 \param    alStatus: requested state
 \param    alStatusCode: value for the AL-Status register

 \brief    This function changes the state of the EtherCAT slave if the requested state
             is lower than the actual state, otherwise the error condition will be reset.
*////////////////////////////////////////////////////////////////////////////////////////

void ECAT_StateChange(UINT8 alStatus, UINT16 alStatusCode)
{
    UINT8 Status = alStatus;

    if(bEcatWaitForAlControlRes)
    {
        /*State transition is pending*/

        if(bApplEsmPending)
        {
            /*The generic stack has currently control of the state transition.
            In case on an local error force ESM timeout*/
            if(alStatusCode != 0)
            {
                bLocalErrorFlag = TRUE;
                u16LocalErrorCode = alStatusCode;
                EsmTimeoutCounter = 0;
            }
        }
        else
        {
            /*complete the state transition*/

            if(alStatusCode != 0)
            {
                bLocalErrorFlag = TRUE;
                u16LocalErrorCode = alStatusCode;

                /*State transition failed due to local application reasons*/
                switch(nEcatStateTrans)
                {
                    case INIT_2_PREOP:
                    case INIT_2_BOOT:
                          APPL_StopMailboxHandler();
                          MBX_StopMailboxHandler();
                    break;
                    case PREOP_2_SAFEOP:
                          APPL_StopInputHandler();
                          StopInputHandler();
                    break;
                    case SAFEOP_2_OP:
                          APPL_StopOutputHandler();
                          StopOutputHandler();
                    break;
                }

                /*In case of a failed state transition the */
                Status =  (UINT8)(nEcatStateTrans >> 4);
            }
            else
            {
                /*State transition succeed*/

                switch(nEcatStateTrans)
                {
                    case INIT_2_PREOP:
                    case INIT_2_BOOT:
                        bMbxRunning = TRUE;
                    break;
                    case PREOP_2_SAFEOP:
                        bEcatInputUpdateRunning = TRUE;
                    break;
                    case SAFEOP_2_OP:
                          bEcatOutputUpdateRunning = TRUE;
                    break;
                }

                /*In case of a failed state transition the */
                Status =  (UINT8)(nEcatStateTrans & STATE_MASK);
            }
                /*Pending state transition finished => write AL Status and AL Status Code*/
                bEcatWaitForAlControlRes = FALSE;

                if(alStatusCode != 0)
                    Status |= STATE_CHANGE;

                SetALStatus(Status,alStatusCode);

        }// state transition need to be completed by the local application
    }//State transition pending
    else
    {
        if ( alStatusCode != 0 )
        {
            /* Local error has happened, we change the state if necessary */
            bLocalErrorFlag = TRUE;
            u16LocalErrorCode = alStatusCode;

            if ( (alStatus & STATE_MASK) < (nAlStatus & STATE_MASK) )
            {
                AL_ControlInd(alStatus, alStatusCode);
            }
        }
        else if (bLocalErrorFlag)
        {
            /*a local error is gone */
            if ( (nAlStatus & STATE_MASK) == (STATE_SAFEOP | STATE_OP) )
            {
                if(nPdOutputSize > 0)
                {
                    /* we have to enable the output process data SyncManger (default: SM2),
                    because it was disabled when switching back to SAFE-OP */
                    HW_EnableSyncManChannel(PROCESS_DATA_OUT);
                }
                else if (nPdInputSize > 0)
                {
                    /* we have to enable the input process data SyncManger (default: SM3),
                    because it was disabled when switching back to SAFE-OP */
                    HW_EnableSyncManChannel(PROCESS_DATA_IN);
                }
            }
            bLocalErrorFlag = FALSE;
            u16LocalErrorCode = 0x00;
        }
    }
}

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

 \brief    初始化从站接口(SM、邮箱、全局变量、状态机、COE初始化)
*////////////////////////////////////////////////////////////////////////////////////////

void ECAT_Init(void)
{
    UINT8 i;                                       //定义8位整形变量
    /*Get Maximum Number of SyncManagers获得SM最大的数目*/
    UINT16 TmpVar = 0;                             //定义16位整形变量

    HW_EscReadWord(TmpVar, ESC_COMM_INFO_OFFSET);  //读FMMU数  0-8个可配置

    TmpVar = SWAPWORD(TmpVar);                     //交换字  高低8位互换
    nMaxSyncMan = (UINT8) ((TmpVar & ESC_SM_CHANNELS_MASK)>> ESC_SM_CHANNELS_SHIFT);   /*nMaxSyncMan变量中8位表示当前需要配置的SM通道数,
                                                                                                                                                          ,用于下面使能代码 ,   执行完后留下TmpVar的低8位*/

    /*  Sync Manager channels,初始化时将所有的SM通道屏蔽,在应用层中根据需要使能相应的SM通道*/
    for (i = 0; i < nMaxSyncMan; i++)              //不使能所有的单元
        HW_DisableSyncManChannel(i);               //每个SM通道操作不使能

    /* initialize the mailbox handler */
    MBX_Init();                                    //邮箱通信机制初始化

    /* initialize variables */
    bApplEsmPending = FALSE;                       //AL访问ESM标志
    bEcatWaitForAlControlRes = FALSE;              //ESCAT等待AL控制寄存器
    bEcatFirstOutputsReceived = FALSE;             //ESCAT输入输出正确标志mainloop函数中用
     bEcatOutputUpdateRunning = FALSE;             //运行模式下,输出更新运行标志mainloop函数中用
     bEcatInputUpdateRunning = FALSE;              //安全运行或运行模式下、输入更新运行标志mainloop函数中用
    bWdTrigger = FALSE;                            //SM2看门狗使能不使能标志
    EcatWdValue = 0;
    Sync0WdCounter = 0;
    Sync0WdValue = 0;
    bDcSyncActive = FALSE;                         //分布时钟同步使能,mainloop函数中用
    bLocalErrorFlag = FALSE;
    u16LocalErrorCode = 0x00;                      //错误标志

    u16ALEventMask = 0;                            //在预运行和安全运行状态下将被赋给0X204 

    /* initialize the AL Status register */
    nAlStatus    = STATE_INIT;                     //AL状态赋值0X01   初始化状态
    SetALStatus(nAlStatus, 0);                     //初始化通信变量和外设灯控制情况  ,只设置al  故障状态指示led
    nEcatStateTrans = 0;                           //状态切换标志为0
    u8EcatErrorLed = LED_OFF;                      //错误指示灯,运行状态错误指示灯初始值为0 

    bEscIntEnabled = FALSE;                        //ESC中断SM2/3使能标志,mainloop函数中用
    /* initialize the COE part */
    COE_Init();                                    //COE部分变量初始化
}

/////////////////////////////////////////////////////////////////////////////////////////
/**
 \brief        这个函数被周期性得调用..主要完成非周期数据处理
*////////////////////////////////////////////////////////////////////////////////////////

void ECAT_Main(void)
{
    UINT16 ALEventReg;
    UINT16 EscAlControl = 0x0000;
    UINT16 sm1Activate = SM_SETTING_ENABLE_VALUE;//0x0001//SM使能

    /* 检查是否有服务存储在邮箱里面 */
    MBX_Main();
    if ( bMbxRunning )/*判断邮箱是否在使能状态*/
		 /* 从站至少工作在PREOP状态,邮箱才可以运行 */
        /* 获得SM1(寄存器0x80E)的Activate-字节来检查是否重复请求被接收 */
    {
        HW_EscReadWord(sm1Activate,(ESC_SYNCMAN_ACTIVE_OFFSET + SIZEOF_SM_REGISTER));
		//#define ESC_SYNCMAN_ACTIVE_OFFSET  0x0806   SM有效寄存器*/
        //#define SIZEOF_SM_REGISTER  8 /**<每个SM有8位配置/状态寄存器.*/
		//#define HW_EscReadWord(WordValue, Address) ((WordValue) = bsp_read_word(Address))
	    //即sm1Activate=bsp_read_word((ESC_SYNCMAN_ACTIVE_OFFSET + SIZEOF_SM_REGISTER));
        sm1Activate = SWAPWORD(sm1Activate);
    }

    /* Read AL Event-Register from ESC */
    ALEventReg = HW_GetALEventRegister();/* 读0x0220寄存器*/
    ALEventReg = SWAPWORD(ALEventReg);

    if ((ALEventReg & AL_CONTROL_EVENT) && !bEcatWaitForAlControlRes)
    {
        /*  读应用层状态控制寄存器,
          得到主站发送的状态改变指令,同时复位应用层事件请求寄存器
          的0位: 状态控制寄存器改变事件) */
        HW_EscReadWord( EscAlControl, ESC_AL_CONTROL_OFFSET);
        EscAlControl = SWAPWORD(EscAlControl);

         /* 重置AL控制事件和SM转变事件(因为SM设置将会被检查在AL_ControlInd里面 )*/
        ALEventReg &= ~((AL_CONTROL_EVENT) | (SM_CHANGE_EVENT));

        AL_ControlInd((UINT8)EscAlControl, 0); /* in AL_ControlInd the state transition will be checked and done */

        /* SM-Change-Event 也被操作 */
    }

    if ( (ALEventReg & SM_CHANGE_EVENT) && !bEcatWaitForAlControlRes && (nAlStatus & STATE_CHANGE) == 0 && (nAlStatus & ~STATE_CHANGE) != STATE_INIT )
    {
         /* SM的转换被设置(寄存器0x220里面的第4位),Sync Manager通道的当6位(使能,低字节寄存器的0x806,0x80E,0x816……)被写 */
        ALEventReg &= ~(SM_CHANGE_EVENT);

        /* 带实际状态的AL_ControlInd函数被调用,所以,正确的SM设置将被检查 */
        AL_ControlInd(nAlStatus & STATE_MASK, 0);
    }

    if(bEcatWaitForAlControlRes)
    {
        AL_ControlRes();
    }
   /*<span style="white-space:pre">    </span>邮箱事件的处理顺序被改变防止竞争条件错误.
        SM1的激活字符(寄存器0x80E)被读,在读AL 事件寄存器之前.
        1. 处理邮箱读事件
        2. 处理重复计划请求
        3. 处理邮箱写事件Handle Mailbox write event
    */
    if ( bMbxRunning )
    {
        /* 从站至少工作在PREOP状态,邮箱才可以运行 */
        /* 获得SM1(寄存器0x80E)的Activate-字节来检查是否重复请求被接收 */
        if(!(sm1Activate & SM_SETTING_ENABLE_VALUE))
            AL_ControlInd(nAlStatus & STATE_MASK, 0);

        if ( ALEventReg & (MAILBOX_READ_EVENT) )
        {
             /* SM 1 (邮箱读事件) 事件被设置,当邮箱由主站读的时候,来响应事件,邮箱里的第一个字节被写,通过写邮箱的第一个字节,邮箱也被锁 */
            u16dummy = 0;
            HW_EscWriteWord(u16dummy,u16EscAddrSendMbx);

           /* 邮箱读事件在变量,ALEventReg应该被重置,在调用MBX_MailboxReadInd函数之前,一个新的邮箱数据包(如果可用)应该被存储在发送邮箱里面。 */
            ALEventReg &= ~(MAILBOX_READ_EVENT);
            MBX_MailboxReadInd();
        }

        DISABLE_MBX_INT;
       /* bMbxRepeatToggle 保持上个状态的Repeat位(Bit1) */  

        if ( ( (sm1Activate & SM_SETTING_REPAET_REQ_MASK) && !bMbxRepeatToggle )
            ||( !(sm1Activate & SM_SETTING_REPAET_REQ_MASK) && bMbxRepeatToggle ))
        {
            /* 重复位(位1)被触发,这里有个一重复请求,在MBX_MailboxRepeatReq函数里,正确的响应将会再次放入发送邮箱 */
            MBX_MailboxRepeatReq();
             /* 响应重复请求在发送邮箱被更新,通过写入重复位RepeatAck Bit(第一位)在SM1的PDI控制字节(寄存器0x80F)acknowledge the repeat request after the send mailbox was updated by writing the Repeat Bit
               in the Repeat Ack Bit (Bit 1) of the PDI Ctrl-Byte of SM 1 (Register 0x80F) */
            if(bMbxRepeatToggle)
                sm1Activate |= SM_SETTING_REPEAT_ACK; //set repeat acknowledge bit (bit 9)
            else
                sm1Activate &= ~SM_SETTING_REPEAT_ACK; //clear repeat acknowledge bit (bit 9)

            sm1Activate = SWAPWORD(sm1Activate);
            HW_EscWriteWord(sm1Activate,(ESC_SYNCMAN_ACTIVE_OFFSET + SIZEOF_SM_REGISTER));
        }
        ENABLE_MBX_INT;

         /* 重新加载ALEvent,因为它可以被改变由于SM的去使能,使能以至于重复请求 */
        ALEventReg = HW_GetALEventRegister();
        ALEventReg = SWAPWORD(ALEventReg);

        if ( ALEventReg & (MAILBOX_WRITE_EVENT) )
        {
           /* SM 0 (邮箱写操作) 事件被设置,当邮箱由主站写来响应事件,邮箱的第一个字节可以被读,它将会在MBX_CheckAndCopyMailbox函数里面被操作event is set, when the mailbox was written from the master,
               to acknowledge the event the first byte of the mailbox has to be read,
               which will be done in MBX_CheckAndCopyMailbox */
            /* 邮箱写事件在变量ALEventReg应该被重置,在调用MBX_CheckAndCopyMailbox之前,在哪里接收邮箱的数据包将会被处理 */
            ALEventReg &= ~(MAILBOX_WRITE_EVENT);
            MBX_CheckAndCopyMailbox();
        }
    }
}

/** @} */
				
时间: 2024-11-05 12:09:43

ecatslv.c及注释的相关文章

Python_01_变量_注释_input_if_缩进

个人笔记,仅作学习记录,如有错误烦请指正 变量命名规则: 1:变量名必须以英文字母.下划线.数字组成的组合2:变量名开头不能是数字3:变量名不能是Python中的关键字4:变量名不能是中文5:Python中的变量名如有多个单词建议下划线连接(其他语言常用驼峰法)6:Python中无法定义常量:在python里面所有的变量都是可变的,所以用全大写的变量名来表示常量 变量赋值:name1 = "laowang"name2 = name1name1 = "xiaozhang&quo

Java-认识变量、注释并能及时发现错误

package com;//变量的演示public class VarDemo { public static void main(String[] args) { /* * 1)题目不用抄 2)注释不用写 3)有错必须改 * * 练习: * 1)声明一个整型的变量,名为a * 声明两个整型的变量,名为b,c * 2)声明整型变量d并赋值为56 * 声明整型变量e, * 给变量e赋值为56 * 3)声明整型变量f并赋值为5, * 声明整型变量g并赋值为f+20,输出g * 声明整型变量h并赋值为

HTML5 &lt;ruby&gt;注释标签

今天学了HTML5的ruby标签,觉得挺有趣的,来记录一下. ruby可以作注释标签,内部有rp和rt标签. <ruby>  标记定义注释或音标. <rp>    告诉那些不支持ruby元素的浏览器该如何显示. <rt>      标记定义对ruby注释的内容文本. 学完这个标签的第一反应就是,我有方法给那些不会读的日语单词做假名注释啦!!! 代码如下,来给一句日语做个小注释: <!DOCTYPE html> <html lang="en&q

IE条件注释

条件注释是IE专门提供的一种语法,其他浏览器会将其作为注释而忽略这些语句. 作用:根据不同的IE版本加载对应的CSS或者JS文件,甚至css代码和html代码. 重要提示 自IE10起,标准模式不再支持条件注释.而是采用特征检测给浏览器不支持的功能来提供备用策略.有关标准模式的详细信息,请参阅定义文档兼容性. 术语 熟悉下列术语有助于你学习文档兼容性. 名词 描述 expression 由运算符.特征和(或)值组合形成一个条件语句 downlevel browser 任何浏览器除了IE5+,其他

Java注释

注释(commentary )是程序中用于说明和解释的一段文字对程序运行不起作用.程序 中添加注释的目的是增强程序的可读性. Java提供3种注释方式:. 单行注释:// 多行注释/**/ 文档注释: /** *文档注释用于从源代码自动生成文档执行javadoc *命名根据源代码中的内容生成网页 *@XXX <-- 可以加入javadoc参数产生相应的文档 */ 不同格式的注释可以嵌套. // Welcome1.java. Text-printing program. /*计信学院09软件工程2

Eclipse注释模板设置详解

设置注释模板的入口:Window->Preference->Java->Code Style->Code Template 然后展开Comments节点就是所有需设置注释的元素.本文现就每一个元素逐一给大家介绍一下. 文件(Files)注释标签: 1 2 3 4 5 6 7 8 /** * @Title: ${file_name} * @Package ${package_name} * @Description: ${todo}(用一句话描述该文件做什么) * @author $

delphi 属性 参数 新注释

delphi 属性 参数 新注释,在写代码的时候,可以自动看到属性.参数的的备注说明,太方便了. Tmyclass=class /// <summary> /// 姓名 /// </summary> name:string; /// <summary> /// 性别 /// </summary> sex:string; end; var aclass: Tmyclass; begin aclass.name; aclass.sex; 鼠标放上去的时候提示 写

vi/vim多行注释和取消注释

多行注释: 1. 进入命令行模式,按ctrl + v进入 visual block模式,然后按j, 或者k选中多行,把需要注释的行标记起来 2. 按大写字母I,再插入注释符,例如// 3. 按esc键就会全部注释了 取消多行注释: 1. 进入命令行模式,按ctrl + v进入 visual block模式,按字母l横向选中列的个数,例如 // 需要选中2列 2. 按字母j,或者k选中注释符号 3. 按d键就可全部取消注释 对单行注释:CTRL_C对多行注释: 先”V”,进入块选择模式.选择一段代

Qt的语法高亮类(注释方式)

1 //语法高亮---QSyntaxHighlighter 2 //highlighter.h 3 class Highlighter : public QSyntaxHighlighter //定义一个类继承自QSyntaxHightliaghter 4 { 5 Q_OBJECT //Qt宏定义,使用Qt元编程 6 7 public: 8 Highlighter(QTextDocument *parent = 0); //构造函数,传递一个QTextDocument对象给其父类 9 10 pr