内容创作者一定要学会在飞书多维表上用Sora大模型!功能太强大了
2026/1/16 20:00:44
///////////////////////////////////////////////////////////////////////////////////////// /** \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 }