AL_ControlRes代码中文注释

///////////////////////////////////////////////////////////////////////////////////////// /** * \brief 应用程序控制响应函数 (Application Control Response)。 * \details 此函数由协议栈周期性地调用,用于处理由应用程序触发的、需要异步完成的状态转换。 * 当状态转换因等待应用程序准备而暂停时(`bEcatWaitForAlControlRes == TRUE`), * 此函数负责监控超时并最终完成或拒绝该转换。 * \note 关键机制: * 1. **暂停转换**:当应用程序的 `APPL_StartXxxHandler` 函数返回 `NOERROR_INWORK` 时, * 表示应用层需要时间准备,状态转换进入暂停等待状态。 * 2. **超时处理**:协议栈通过 `EsmTimeoutCounter` 为每次暂停的转换计时。 * 若超时前应用未完成准备,则转换失败,状态回退,并设置相应的错误码。 * 3. **应用完成**:应用程序在准备就绪后,必须调用 `ECAT_StateChange()` 来告知协议栈, * 这将间接导致 `bApplEsmPending` 被置为 `FALSE`,并在下一次 `AL_ControlRes` 被调用时完成转换。 * 4. **结果提交**:无论成功或失败,最终通过 `SetALStatus()` 将新状态和状态码写入 ESC 寄存器,通知主站。 */ ///////////////////////////////////////////////////////////////////////////////////////// void AL_ControlRes(void) { // 检查是否存在一个由应用程序触发、正在等待其异步完成的状态转换 if(bEcatWaitForAlControlRes) { UINT16 result = 0; // 存储应用程序启动函数的返回值 UINT8 Status = 0; // 待设置的目标AL状态 (STATE_PREOP, STATE_SAFEOP, STATE_OP) UINT16 StatusCode = 0; // 待设置的AL状态码 (0=成功,非零=错误码) // 情况一:ESM(EtherCAT状态机)等待超时,应用程序未能在规定时间内完成准备 if(EsmTimeoutCounter == 0) { // 超时后,目标状态应回退到转换发起前的状态(右移4位获取源状态) Status = (UINT8)(nEcatStateTrans >> 4); // 根据超时的具体转换类型,执行清理并设置相应的错误码 switch(nEcatStateTrans) { // 转换类型:INIT -> PREOP 或 INIT -> BOOT(邮箱初始化阶段) case INIT_2_PREOP: case INIT_2_BOOT: #if MAILBOX_SUPPORTED // 如果应用程序曾被告知转换开始(bApplEsmPending为TRUE),则通知其停止 if(!bApplEsmPending) APPL_StopMailboxHandler(); // 应用层邮箱停止处理 MBX_StopMailboxHandler(); // 协议栈邮箱停止处理 #endif // 决定上报的错误码:优先使用应用层设置的本地错误码 if(bLocalErrorFlag) { StatusCode = u16LocalErrorCode; // 应用层自定义错误 } else { StatusCode = ALSTATUSCODE_UNSPECIFIEDERROR; // 协议栈默认未指定错误 } break; // 退出switch // 转换类型:PREOP -> SAFEOP(过程数据输入初始化阶段) case PREOP_2_SAFEOP: if(!bApplEsmPending) APPL_StopInputHandler(); // 应用层输入停止处理 StopInputHandler(); // 协议栈输入停止处理 if(bLocalErrorFlag) { StatusCode = u16LocalErrorCode; } else { StatusCode = ALSTATUSCODE_UNSPECIFIEDERROR; } break; // 转换类型:SAFEOP -> OP(过程数据输出激活阶段) case SAFEOP_2_OP: #if DC_SUPPORTED // 如果支持分布式时钟(DC)同步 if(bDcSyncActive) // 如果DC同步已被激活 { // DC模式下,对超时原因做精确诊断,设置更具体的错误码 if(!bDcRunning) // 原因1:未收到Sync0同步信号 { StatusCode = ALSTATUSCODE_NOSYNCERROR; } else if(!bEcatFirstOutputsReceived) // 原因2:未收到主站发来的首帧输出过程数据 { StatusCode = ALSTATUSCODE_SMWATCHDOG; // 同步管理器看门狗超时 } else // 原因3:其他可能,如锁相环(PLL)未同步 { StatusCode = ALSTATUSCODE_DCPLLSYNCERROR; } } else // 不支持DC或DC未激活 #endif { // 非DC模式下的处理逻辑 #if !OP_PD_REQUIRED // 如果从站允许不依赖过程数据就进入OP状态(较少见) /* 即使超时,也强制设置为有效的OP状态转换 */ Status = STATE_OP; StatusCode = 0; // 无错误 bEcatOutputUpdateRunning = TRUE; // 标记输出过程数据更新已运行 #else // 通常情况:进入OP状态必须接收到过程数据 StatusCode = ALSTATUSCODE_SMWATCHDOG; // 因未收到数据而超时 #endif } // 如果因错误导致转换失败(StatusCode != 0),需要停止已启动的输出处理 if(StatusCode != 0) { if(!bApplEsmPending) APPL_StopOutputHandler(); // 应用层输出停止处理 StopOutputHandler(); // 协议栈输出停止处理 } break; } // 结束超时处理的switch } // 结束 if(EsmTimeoutCounter == 0) 超时处理分支 // 情况二:ESM 尚未超时,尝试调用应用程序的启动函数以完成转换 else { // 检查当前正在进行的具体转换类型,并调用对应的应用程序启动函数 switch(nEcatStateTrans) { // 转换类型:INIT -> PREOP 或 INIT -> BOOT case INIT_2_PREOP: case INIT_2_BOOT: // 检查应用程序是否已经准备好完成转换(bApplEsmPending 由应用调用 ECAT_StateChange() 后清除) if(bApplEsmPending) { bApplEsmPending = FALSE; // 清除挂起标志,表示应用已响应 #if MAILBOX_SUPPORTED // 调用应用层邮箱启动函数(应用在此函数中完成邮箱相关初始化) result = APPL_StartMailboxHandler(); if(result == 0) // 应用层启动成功 { bMbxRunning = TRUE; // 设置协议栈邮箱运行标志 // 设置目标状态为本次转换的目标(nEcatStateTrans的低4位) Status = (UINT8)(nEcatStateTrans & STATE_MASK); } else // 应用层启动失败 { /* 应用程序特定的转换失败。 (如果返回NOERROR_INWORK,转换仍处于挂起状态,等待应用后续调用ECAT_StateChange完成) */ if(result != NOERROR_INWORK) // 如果是非“进行中”的明确错误 { // 启动失败,需要执行清理:停止应用层和协议栈的邮箱处理 APPL_StopMailboxHandler(); MBX_StopMailboxHandler(); // 注意:此处未设置Status,因此外层if(Status!=0)不成立,转换保持挂起, // 等待后续超时或应用再次尝试。错误码将在超时分支中设置。 } } #endif } break; // 转换类型:PREOP -> SAFEOP case PREOP_2_SAFEOP: if(bApplEsmPending) { bApplEsmPending = FALSE; // 调用应用层输入启动函数,传入AL事件掩码指针,应用可修改需要使能的中断事件 result = APPL_StartInputHandler(&u16ALEventMask); if(result == 0) { bEcatInputUpdateRunning = TRUE; // 设置协议栈输入更新运行标志 Status = STATE_SAFEOP; // 目标状态为SAFEOP } else { if(result != NOERROR_INWORK) // 明确失败,非“进行中” { APPL_StopInputHandler(); StopInputHandler(); } } } break; // 转换类型:SAFEOP -> OP case SAFEOP_2_OP: if(bApplEsmPending) { #if DC_SUPPORTED // DC同步模式下的特殊处理:需要等待PLL(锁相环)锁定稳定 if(bDcSyncActive) { // 检查是否已等待足够时间让PLL稳定(i16WaitForPllRunningCnt由DC_CheckWatchdog递增) if(i16WaitForPllRunningTimeout > 0 && i16WaitForPllRunningTimeout <= i16WaitForPllRunningCnt) { // PLL稳定时间满足,清除等待计数器 i16WaitForPllRunningTimeout = 0; i16WaitForPllRunningCnt = 0; // 调用应用层输出启动函数 result = APPL_StartOutputHandler(); if(result == 0) { bEcatOutputUpdateRunning = TRUE; Status = STATE_OP; } else { if(result != NOERROR_INWORK) { APPL_StopOutputHandler(); StopOutputHandler(); } } } // 如果PLL稳定时间未到,则什么也不做,等待下次AL_ControlRes被调用时再检查 } else // 非DC同步模式 #endif { // 标准处理:通常只需直接启动输出处理 #if OP_PD_REQUIRED // 如果从站配置为必须收到过程数据才能进OP // 确保要么没有输出数据(nPdOutputSize==0),要么已经收到了第一帧输出数据 if(nPdOutputSize == 0 || bEcatFirstOutputsReceived) #endif { result = APPL_StartOutputHandler(); if(result == 0) { bEcatOutputUpdateRunning = TRUE; Status = STATE_OP; } else { if(result != NOERROR_INWORK) { APPL_StopOutputHandler(); StopOutputHandler(); } } } // 如果 OP_PD_REQUIRED 为真,但既不满足 nPdOutputSize==0 也不满足 bEcatFirstOutputsReceived, // 则不会调用 APPL_StartOutputHandler,Status保持为0,转换继续挂起等待。 } } break; }// 结束switch - 根据转换类型处理 } // 结束 else(未超时处理分支) // 判断是否已经得到了一个明确的最终状态(成功或失败) if(Status != 0) { /* 暂停的状态转换处理结束 => 写入AL状态和状态码到ESC寄存器,通知主站 */ bEcatWaitForAlControlRes = FALSE; // 清除等待标志,允许新的状态转换请求 // 如果状态码非零(表示转换失败),需要在状态字节中设置错误指示位(STATE_CHANGE) if(StatusCode != 0) Status |= STATE_CHANGE; // 调用关键函数,将最终状态和状态码写入ESC的AL状态寄存器(0x130)和AL状态码寄存器(0x134) SetALStatus(Status, StatusCode); } // 如果 Status 仍为 0,表示转换仍需等待(可能因为应用未就绪或PLL稳定时间未到), // 则不执行任何操作,保持挂起状态,等待下一次 AL_ControlRes 被周期性调用。 }// 结束 if (bEcatWaitForAlControlRes) - 整个函数仅在有挂起转换时执行 }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1190854.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Makefile中 =、:=和 ?=的使用方法

理解Makefile中 、:和 ?这三个赋值操作符的区别&#xff0c;对编写可靠高效的构建脚本至关重要。下面这个表格能帮你快速把握它们的核心差异。特性(递归扩展赋值):(简单扩展赋值)?(条件赋值)赋值时机​变量被使用&#xff08;引用&#xff09;时才展开求值变量定义时就立即展…

2026.1.10 作业 - # P14063 [PO Final 2022] 海滩 / Badstrand

2026.1.10 作业 - # P14063 [PO Final 2022] 海滩 / Badstrand题目描述 Maja 厌倦了海岸被大湖占据,她想要修建一个又长又漂亮的公用海滩。现在,她计划买下海岸边的一块土地来建造海滩。 Maja 预算为 \(B\) 克朗。有…

AndroidStudio汉化步骤

代码视图切换按钮&#xff1a;

突破AI产品经理求职难关:技术认知、产品思维与落地能力三大必修课

文章介绍了AI产品经理必备的三大核心能力&#xff1a;技术直觉与认知边界&#xff08;理解技术基础概念和边界&#xff09;、AI产品感&#xff08;从用户真实需求出发创造价值&#xff09;、AI产品的落地与评估&#xff08;具备落地经验和科学评估方法&#xff09;。优秀的AI产…

基于模块化设计的可定制多领域推理系统

基于模块化设计的可定制多领域推理系统 关键词:模块化设计、可定制、多领域推理系统、推理算法、应用场景 摘要:本文围绕基于模块化设计的可定制多领域推理系统展开深入探讨。首先介绍了该系统的背景,包括目的、预期读者、文档结构和相关术语。接着阐述了核心概念与联系,给…

C++ 线程互斥锁 lock_guard

std::lock_guard是 C11 标准库提供的RAII 风格的互斥锁封装类&#xff0c;核心目的是自动管理互斥锁的加锁 / 解锁&#xff0c;从根本上避免 “忘记解锁导致死锁”“异常导致锁无法释放” 这类低级且致命的错误。一、先理解核心&#xff1a;RAII 设计思想lock_guard的底层是RAI…

大模型应用工程师崛起之路:从入门到年薪60万+的完整指南

本文全面解析大模型应用工程师职业&#xff0c;介绍其定义、职责及广阔就业前景。数据显示该岗位70.8%月薪达20K-50K&#xff0c;年薪24-60万。文章提供系统学习路径&#xff0c;包括Python入门、大模型核心原理、Transformer架构、微调技术及企业级实战项目。职业发展可走技术…

人工智能应用-机器视觉:绘画大师 04.​​​​​​​​​​​​​​基于风格迁移的绘画大师

利用深度神经网络的这种内容&#xff0d;风格分离能力可以实现图片的风格迁移&#xff0c;即将一张图片 B 的风格迁移到另一张图片 A 上。换句话说&#xff0c;就是希望得到一张图片&#xff0c;该图片在内容上与 A 一致&#xff0c;但在风格上与 B 一致。实现这一目标的方法如…

计算机大数据毕设实战-基于django的蔬菜销售分析与预测可视化系统蔬菜产品销售预测可视化系统设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】

java毕业设计-基于springboot的(源码LW部署文档全bao远程调试代码讲解等) 博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、…

C++ 实现【精准可控】内存占用测试工具(指定内存大小,实打实占用物理内存,亲测可用)

前言在做程序性能验证、硬件资源测试、帧率影响实验&#xff08;比如验证内存占用量对摄像头 / 图像处理 / 算法推理帧率的影响&#xff09;时&#xff0c;我们经常需要人为、精准的占用指定大小的内存空间&#xff0c;以此模拟不同的内存负载环境。Windows 自带的内存查看工具…

typescript-类的静态属性和静态方法

我们上一节看到了类&#xff0c;里面都是类的实例属性和实例方法&#xff0c;即需要实例化后才可以进行访问的。什么是静态属性和静态方法&#xff1f;静态属性和静态方法是不需要实例化就可以访问的属性和方法(不需要实例化是指不需要new来生成对象)。还是以上一节的Person类举…

解锁AI记忆新范式:人类情景记忆如何提升大模型性能

本文探讨了如何借鉴人类情景记忆机制改进记忆增强型大语言模型。当前AI记忆系统在数据使用上低效且不符合人类认知直觉。文章对比了LLM与人脑记忆系统的五大关键差异&#xff1a;动态更新、事件分割、选择性、时间连续性和检索竞争。通过引入类人记忆机制&#xff0c;不仅能让A…

人工智能应用-机器视觉:绘画大师 05.还原毕加索的隐藏画

在艺术史上&#xff0c;一些大画家也曾经历过艰难时刻。例如&#xff0c;毕加索在 1901—1904 年间经历了极度的经济困境。 为了节省开支&#xff0c;他不得不在已经使用过的画布上创作新作品。如图 26.7所示&#xff0c;通过 X 射线扫描&#xff0c;人们发现毕加索在这一时期…

揭秘!提示工程架构师优化提示系统用户参与策略的关键技巧

揭秘&#xff01;提示工程架构师优化提示系统用户参与策略的关键技巧 一、引言&#xff1a;为什么你精心设计的AI系统&#xff0c;用户只用了一次&#xff1f; 上周&#xff0c;我朋友小A的吐槽让我印象深刻——他花了一个月搭建的AI旅游助手&#xff0c;上线3天用户留存率只…

【教程4>第10章>第25节】基于FPGA的图像Robert变换开发——理论分析与matlab仿真

目录 1.软件版本 2.图像Robert变换理论概述 3.图像Robert变换提取的matlab仿真测试 欢迎订阅FPGA/MATLAB/Simulink系列教程 《★教程1:matlab入门100例》 《★教程2:fpga入门100例》 《★教程3:simulink入门60例》 《★教程4:FPGA/MATLAB/Simulink联合开发入门与进阶X例》

学霸同款2026继续教育AI论文平台TOP10:毕业论文写作全测评

学霸同款2026继续教育AI论文平台TOP10&#xff1a;毕业论文写作全测评 2026继续教育AI论文平台测评&#xff1a;选对工具&#xff0c;提升写作效率 在当前学术环境日益严格的背景下&#xff0c;继续教育群体在撰写毕业论文时面临诸多挑战&#xff0c;如选题困难、文献检索繁琐、…

AAAI 2025论文分享|Agent4Edu:基于大语言模型生成式智能体的个性化学习模拟器

本推文介绍了AAAI 2025收录的一篇论文《Agent4Edu: Generating Learner Response Data by Generative Agents for Intelligent Education Systems》。Agent4Edu是一种基于大语言模型的个性化学习模拟器&#xff0c;旨在解决智能教育系统中高质量学习者响应数据稀缺、传统模拟方…

空气能十大领军品牌盘点:绿色能源时代的创新力量 - 资讯焦点

在“双碳”目标全面推进和清洁能源转型的浪潮中,空气能行业正迎来前所未有的发展机遇。作为高效、环保、可再生的能源利用方式,空气能技术已在采暖、制冷、热水等多个领域展现出强大的竞争力和市场潜力。本文盘点当前…

2025 AI大模型薪资狂欢:小白程序员入行最后黄金时机,年薪百万不是梦!非常详细建议收藏

文章分析了2025年AI大模型领域高薪就业趋势&#xff0c;指出供需失衡和政策支持导致AI岗位薪资暴涨&#xff0c;大模型算法工程师平均月薪7万。文章介绍五大高薪岗位及所需技能&#xff0c;提供提升竞争力的方法&#xff0c;并强调技术红利窗口期正在关闭&#xff0c;现在是入行…

Node.js代码统计神器

统计代码行数使用Node.js编写一个脚本&#xff0c;统计指定目录下所有文件的代码行数。const fs require(fs); const path require(path);function countLinesInFile(filePath) {const content fs.readFileSync(filePath, utf-8);return content.split(\n).length; }functio…