现在的位置: 首页 > 综合 > 正文

往死里写——ECAT_Main()状态机处理

2014年02月06日 ⁄ 综合 ⁄ 共 21912字 ⁄ 字号 评论关闭
/////////////////////////////////////////////////////////////////////////////////////////
/**
 \brief        这个函数被周期性得调用.
*////////////////////////////////////////////////////////////////////////////////////////

void ECAT_Main(void)
{
    UINT16 ALEventReg;
    UINT16 EscAlControl = 0x0000;
#if MAILBOX_SUPPORTED

    UINT8 sm1Activate = SM_SETTING_ENABLE_VALUE;
#endif

#if MAILBOX_SUPPORTED
    /* 检查是否有服务存储在邮箱里面 */
    MBX_Main();


    if ( bMbxRunning )
    {
        /* 从站至少工作在PREOP状态,邮箱才可以运行 */
        /* 获得SM1(寄存器0x80E)的Activate-字节来检查是否重复请求被接收 */
        HW_EscReadByte(sm1Activate,(ESC_SYNCMAN_ACTIVE_OFFSET + SIZEOF_SM_REGISTER));
    }
#endif //#if MAILBOX_SUPPORTED

    /* 从ESC里读取AL 事件-寄存器 */
    ALEventReg = HW_GetALEventRegister();
    ALEventReg = SWAPWORD(ALEventReg);

#if ESC_EEPROM_EMULATION
    if ((ALEventReg & EEPROM_CMD_PENDING)) 
    {
        EEPROM_CommandHandler();
    }
#endif

    if ((ALEventReg & AL_CONTROL_EVENT) && !bEcatWaitForAlControlRes)
    {
        /* AL的控制事件寄存器被设置,获得从主站发过来的AL控制寄存器来响应这个事件(对应的AL事件寄存器对应的位将会被重置) */
        HW_EscReadByte( EscAlControl, ESC_AL_CONTROL_OFFSET);
        /* 重置AL控制事件和SM转变事件(因为SM设置将会被检查在AL_ControlInd里面 )*/
        ALEventReg &= ~((AL_CONTROL_EVENT) | (SM_CHANGE_EVENT));

        AL_ControlInd((UINT8)EscAlControl, 0); /* 在AL_ControlInd函数里面状态转换将被检查和操作 */
        
        /* 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();
    }
#if MAILBOX_SUPPORTED
    /*	邮箱事件的处理顺序被改变防止竞争条件错误.
        SM1的激活字符(寄存器0x80E)被读,在读AL 事件寄存器之前.
        1. 处理邮箱读事件
        2. 处理重复计划请求
        3. 处理邮箱写事件Handle Mailbox write event
    */
    if ( bMbxRunning )
    {
        /*SM转变事件(0x220:4)可以被认可通过读SM1控制寄存器没有给通知给本地应用程序=>检查是否SM1仍然为使能SnycManger change event (0x220:4) could be acknowledged by reading the SM1 control register without notification to the local application
        => check if the SyncManger 1 is still enabled*/
        if(!(sm1Activate & SM_SETTING_ENABLE_VALUE))
            AL_ControlInd(nAlStatus & STATE_MASK, 0);

        if ( ALEventReg & (MAILBOX_READ_EVENT) )
        {
            /* SM 1 (邮箱读事件) 事件被设置,当邮箱由主站读的时候,来响应事件,邮箱里的第一个字节被写,通过写邮箱的第一个字节,邮箱也被锁 */
            u8dummy = 0;
            HW_EscWriteByte(u8dummy,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) */

            sm1Activate &= SM_SETTING_REPEAT_ACK;
            HW_EscWriteByte(sm1Activate,(ESC_SM_PDICONTROL_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();
        }
    }
#endif
}

/////////////////////////////////////////////////////////////////////////////////////////
/**
 \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:
     /* 在预运行状态,只有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:
        /* 在安全运行和运行阶段,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    :
#if BOOTSTRAPMODE_SUPPORTED//如果BOOT状态被支持的话
            /* 如果应用程序需要执行代码当进入BOOT模式,这个在这里被完成 */
            bBootMode = TRUE;
            if ( CheckSmSettings(MAILBOX_READ+1) != 0 )
            {
                bBootMode = FALSE;
                result = ALSTATUSCODE_INVALIDMBXCFGINBOOT;
                break;
            }
#if AL_EVENT_ENABLED
            /* 去使能所有的事件在BOOT的模式 */
            HW_ResetALEventMask(0);
#endif
#if MAILBOX_SUPPORTED
            /* 在(mailbox.c)里的函数MBX_StartMailboxHandler,检查范围邮箱的SM,SM0和SM1之间是否相互重叠,如果结果不等于0,从站将会停留在INIT和设置AL-Status的错误为(位4) */
            result = MBX_StartMailboxHandler();
            if (result == 0)
            {
                bApplEsmPending = FALSE;
                /* 此外,这里有一个应用程序特殊的检查(在ecatappl.c里),如果状态转换从INIT到BOOT应该被完成,如果结果是NOERROR_INWORK,从站将会停留在INIT状态,直到超时或者转换完成在AL_ControlRes函数*/
            
                result = APPL_StartMailboxHandler();
                if ( result == 0 )
                {
                    /*转换完成transition successful*/
                    bMbxRunning = TRUE;
                }
            }

            if(result != 0 && result != NOERROR_INWORK)
            {
                /*停止APPL的邮箱处理,如果APPL开始处理器被调用之前*/
                if(!bApplEsmPending)
                    APPL_StopMailboxHandler();

                 MBX_StopMailboxHandler();
            }
#endif // MAILBOX_SUPPORTED

            BL_Start( STATE_BOOT );
#else
            result = ALSTATUSCODE_BOOTNOTSUPP;
#endif
            break;

        case BOOT_2_INIT    :
#if BOOTSTRAPMODE_SUPPORTED//如果BOOT模式被支持
            if(bBootMode)
            {
                bBootMode = FALSE;
                CheckSmSettings(MAILBOX_READ+1);
#if AL_EVENT_ENABLED//如果AL事件使能
                /* 禁止所有的事件在BOOT状态 */
                HW_ResetALEventMask(0);
#endif
#if MAILBOX_SUPPORTED
                MBX_StopMailboxHandler();
                result = APPL_StopMailboxHandler();
#endif
            }
#else
            result = ALSTATUSCODE_BOOTNOTSUPP;
#endif
#if TIESC_HW//如果支持的是TI的ESC硬件
#ifdef ENABLE_ONLINE_FIRMWARE_UPGRADE
            bsp_boot_2_init_handler();
#endif            
#endif         
            break;
        case INIT_2_PREOP :
#if MAILBOX_SUPPORTED//如果邮箱支持
            {
            /*在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();
            }

            }
#endif
            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)
                {
#if AL_EVENT_ENABLED
                    /* 初始化AL事件屏蔽寄存器(0x204)initialize the AL Event Mask register (0x204) */
                    HW_SetALEventMask( u16ALEventMask );
#endif

                    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:
#if MAILBOX_SUPPORTED
            MBX_StopMailboxHandler();
            result = APPL_StopMailboxHandler();
#endif
            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_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

}

/////////////////////////////////////////////////////////////////////////////////////////
/**
 \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);
    	SMLength = pSyncMan->Length;
    	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     0(AL的状态代码_没有错误ALSTATUSCODE_NOERROR), NOERROR_INWORK
\param      pInputSize  指针指向保存输入过程数据的长度
\param      pOutputSize  指针pointer to save the output process data length

\brief    This function calculates the process data sizes from the actual SM-PDO-Assign
            and PDO mapping
*////////////////////////////////////////////////////////////////////////////////////////
Uint16 APPL_GenerateMapping(Uint16* pInputSize,Uint16* pOutputSize)
{
    Uint16 result = 0;
    Uint16 PDOAssignEntryCnt = 0;
    OBJCONST TOBJECT OBJMEM * pPDO = NULL;
    Uint16 PDOSubindex0 = 0;
    UINT32 *pPDOEntry = NULL;
    Uint16 PDOEntryCnt = 0;
    Uint16 InputSize = 0;
    Uint16 OutputSize = 0;

    /*Scan object 0x1C12 RXPDO assign*/
    for(PDOAssignEntryCnt = 0; PDOAssignEntryCnt < sRxPDOassign.u16SubIndex0; PDOAssignEntryCnt++)
    {
        pPDO = OBJ_GetObjectHandle(sRxPDOassign.aEntries[PDOAssignEntryCnt]);
        if(pPDO != NULL)
        {
            PDOSubindex0 = *((Uint16 *)pPDO->pVarPtr);
            for(PDOEntryCnt = 0; PDOEntryCnt < PDOSubindex0; PDOEntryCnt++)
            {
                pPDOEntry = (UINT32 *)((Uint8 *)pPDO->pVarPtr + (OBJ_GetEntryOffset((PDOEntryCnt+1),pPDO)>>3));        //goto PDO entry
                // we increment the expected output size depending on the mapped Entry 
                OutputSize += (Uint16) ((*pPDOEntry) & 0xFF);
            }
        }
    }
        
    OutputSize = (OutputSize + 7) >> 3;

    /*Scan Object 0x1C13 TXPDO assign*/
    for(PDOAssignEntryCnt = 0; PDOAssignEntryCnt < sTxPDOassign.u16SubIndex0; PDOAssignEntryCnt++)
    {
        pPDO = OBJ_GetObjectHandle(sTxPDOassign.aEntries[PDOAssignEntryCnt]);
        if(pPDO != NULL)
        {
            PDOSubindex0 = *((Uint16 *)pPDO->pVarPtr);
            for(PDOEntryCnt = 0; PDOEntryCnt < PDOSubindex0; PDOEntryCnt++)
            {
                pPDOEntry = (UINT32 *)((Uint8 *)pPDO->pVarPtr + (OBJ_GetEntryOffset((PDOEntryCnt+1),pPDO)>>3));        //goto PDO entry
                // we increment the expected output size depending on the mapped Entry 
                InputSize += (Uint16) ((*pPDOEntry) & 0xFF);
            }
        }
    }
    InputSize = (InputSize + 7) >> 3;

    *pInputSize = InputSize;
    *pOutputSize = OutputSize;
    return result;
}

抱歉!评论已关闭.