当前位置: 首页 > news >正文

ENET_GetRxFrame vs ENET_ReadFrame

一、核心功能差异

1. ENET_GetRxFrame:获取接收帧的数据及缓冲区信息
  • 核心目标:从接收缓冲区描述符(BD,Buffer Descriptor)中解析出完整的接收帧结构,包括帧的缓冲区地址、长度、错误状态等元数据,但不直接拷贝帧数据到用户缓冲区。
  • 作用:为上层提供帧的 “索引” 信息,让用户知道数据存放在哪里,以便后续通过缓冲区地址读取实际数据。
2. ENET_ReadFrame:读取接收帧的实际数据
  • 核心目标:将接收帧的实际数据从硬件缓冲区拷贝到用户提供的data缓冲区中,同时处理缓冲区描述符的更新。
  • 作用:完成数据的最终提取,是用户获取帧内容的直接接口。

两者的本质区别在于数据处理方式

  • ENET_GetRxFrame不直接拷贝数据,仅获取帧的元信息(缓冲区地址、长度、错误状态等),数据仍存放在硬件管理的缓冲区中。
  • ENET_ReadFrame主动拷贝数据到用户提供的缓冲区,完成数据从硬件缓冲区到应用层的转移。

二、代码细节对比分析

1. 输入输出参数差异
接口关键输入参数关键输出参数
ENET_GetRxFrameenet_rx_frame_struct_t *rxFramerxFrame(包含缓冲区数组、总长度等)
ENET_ReadFrameuint8_t *data(用户数据缓冲区)data(填充实际帧数据)
uint32_t length(用户缓冲区长度)uint32_t *ts(时间戳,可选)
  • ENET_GetRxFramerxFrame是一个结构体,用于存储帧的元数据(如rxBuffArray缓冲区数组、totLen总长度、rxFrameError错误状态);
  • ENET_ReadFramedata是用户预分配的字节数组,直接用于存放拷贝的帧数据。
2. 核心逻辑差异
(1)ENET_GetRxFrame的核心逻辑:解析帧结构,不拷贝数据
  • 步骤 1:检查缓冲区描述符(BD)
    循环遍历接收 BD 环(rxBdRing),通过 BD 的EMPTY标志(ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK)判断是否有新帧。若 BD 非空,继续查找带有LAST标志(ENET_BUFFDESCRIPTOR_RX_LAST_MASK)的 BD,确定帧的结束位置。

// 检查当前BD是否为空(无数据)
while (0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK)) {// 查找帧的最后一个BD(带有LAST标志)if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)) {// 解析帧错误状态result = ENET_GetRxFrameErr(...);break;}// ... 移动到下一个BD
}
  • 步骤 2:填充帧元数据
    找到完整帧后,将帧的缓冲区地址(curBuffDescrip->buffer)、长度(curBuffDescrip->length)等信息填入rxFrame->rxBuffArray,并记录总长度(rxFrame->totLen)。

    rxBuffer = &rxFrame->rxBuffArray[index];
    rxBuffer->buffer = (void *)(uint8_t *)address; // 记录缓冲区地址
    rxBuffer->length = curBuffDescrip->length;    // 记录缓冲区长度
    
  • 步骤 3:更新 BD 环状态
    释放已处理的 BD(设置EMPTY标志),为下一次接收准备缓冲区,并激活接收环(ENET_ActiveReadRing)。

(2)ENET_ReadFrame的核心逻辑:拷贝数据,处理缓冲区
  • 步骤 1:判断是否仅更新 BD
    dataNULL,则仅更新 BD 环状态(释放已处理的 BD),不拷贝数据(用于丢弃帧的场景)。

    if (data == NULL) {do {ENET_UpdateReadBuffers(base, handle, ringId); // 更新BD// ... 查找LAST标志的BD} while (...);
    }
    
  • 步骤 2:拷贝帧数据到用户缓冲区
    data非空,则循环读取每个 BD 的缓冲区数据,通过memcpy拷贝到data中,并累加偏移量(offset)。直到遇到带有LAST标志的 BD,完成整帧拷贝。

    dest = (uintptr_t)data + offset;
    // 拷贝当前BD的缓冲区数据到用户缓冲区
    (void)memcpy((void *)(uint8_t *)dest, (void *)(uint8_t *)address, len);
    offset += len; // 累加偏移量,处理多BD拼接的帧
    
  • 步骤 3:处理时间戳(可选)
    若使能增强型 BD(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE),可通过ts输出帧的时间戳。

3. 错误处理差异
  • ENET_GetRxFrame:重点检查帧的完整性(如是否找到LAST标志、长度是否为 0),并通过rxFrame->rxFrameError返回错误类型(如校验错误、溢出等)。
  • ENET_ReadFrame:主要检查用户缓冲区长度是否足够,若拷贝过程中长度不匹配,返回kStatus_ENET_RxFrameFail

三、使用场景区别

  • ENET_GetRxFrame适用场景
    需要先获取帧的元数据(如长度、缓冲区地址),再决定是否读取数据(例如:根据帧长度预分配用户缓冲区,或跳过不需要的帧)。

  • ENET_ReadFrame适用场景
    已知需要读取数据,直接将帧内容拷贝到用户缓冲区(例如:应用层需要解析帧数据时,直接调用此接口获取字节流)。

四、二者对比

维度ENET_GetRxFrameENET_ReadFrame
核心操作解析帧结构,获取元数据(不拷贝数据)拷贝帧数据到用户缓冲区
数据处理方式记录缓冲区地址,由用户后续读取直接完成数据拷贝
典型用途帧过滤、长度检查、错误判断实际数据提取、应用层解析
依赖关系可单独使用(获取元数据)通常需在ENET_GetRxFrame之后使用(已知帧信息)

五、优先选择ENET_GetRxFrame的场景

1. 高性能网络通信(如 TCP/UDP 高吞吐量场景)
  • 原因ENET_GetRxFrame直接返回硬件缓冲区地址(无需拷贝数据),可配合 LwIP 等协议栈的pbuf机制,实现 “零拷贝” 数据传递,减少 CPU 负载。

  • 示例:在 LwIP 中,协议栈需要直接操作硬件缓冲区解析 IP 包,此时ENET_GetRxFrame返回的rxFrame->rxBuffArray可直接映射到pbuf,避免数据拷贝。

    // LwIP接收流程示例
    enet_rx_frame_struct_t rxFrame;
    if (ENET_GetRxFrame(ENET, &handle, &rxFrame, 0) == kStatus_Success) {// 将硬件缓冲区直接封装为pbufstruct pbuf *p = pbuf_alloc(PBUF_RAW, rxFrame.totLen, PBUF_REF);p->payload = rxFrame.rxBuffArray[0].buffer; // 直接使用硬件缓冲区地址netif->input(p, netif); // 递交给LwIP协议栈
    }
    
2. 需要帧过滤或预处理(如根据帧长度 / 类型决定是否处理)
  • 原因ENET_GetRxFrame可先获取帧的元数据(如rxFrame.totLenrxFrame.rxAttribute),无需拷贝完整数据即可判断是否需要进一步处理,节省无效操作。

  • 示例:仅处理长度大于 100 字节的帧,或过滤特定 MAC 地址的帧:

    enet_rx_frame_struct_t rxFrame;
    if (ENET_GetRxFrame(ENET, &handle, &rxFrame, 0) == kStatus_Success) {// 过滤短帧if (rxFrame.totLen < 100) {// 无需处理,直接释放缓冲区ENET_ReleaseRxFrame(...); return;}// 处理有效帧(后续可调用ENET_ReadFrame拷贝数据)
    }
    
3. 多缓冲区拼接的帧(如超过 MTU 的大数据帧)
  • 原因: ENET 控制器可能将长帧拆分到多个 BD(缓冲区描述符)中,ENET_GetRxFrame会自动解析多个 BD 的关联关系,返回完整的帧长度和缓冲区数组,简化长帧处理。
  • 优势:无需用户手动拼接多个 BD 的缓冲区,降低代码复杂度。

六、优先选择ENET_ReadFrame的场景

1. 简单数据接收(如固定格式的自定义协议)
  • 原因:若应用层只需直接获取帧的字节流(如解析简单的自定义协议),ENET_ReadFrame可一步完成数据拷贝,代码更简洁,无需处理硬件缓冲区细节。

  • 示例:读取并解析一个固定长度的控制帧:

    uint8_t data[128];
    uint32_t len = 128;
    if (ENET_ReadFrame(ENET, &handle, data, len, 0, NULL) == kStatus_Success) {// 直接解析data中的自定义协议parse_custom_protocol(data, len);
    }
    
2. 需要长期保存数据(脱离硬件缓冲区生命周期)
  • 原因:硬件缓冲区由 ENET 驱动管理,在调用ENET_UpdateReadBuffers或下次接收时可能被覆盖。若需长期保存数据(如日志记录),ENET_ReadFrame将数据拷贝到用户缓冲区更安全。
  • 注意ENET_GetRxFrame返回的缓冲区地址仅在当前帧处理周期内有效,不能长期引用。
3. 低吞吐量场景(对性能要求不高)
  • 原因:在数据量小、速率低的场景(如偶尔的配置帧),数据拷贝的开销可忽略,ENET_ReadFrame的简洁性更具优势。

七、总结选择原则

场景特征推荐接口核心原因
高性能 / 高吞吐量(如 LwIP)ENET_GetRxFrame零拷贝,直接操作硬件缓冲区
需要帧过滤 / 预处理ENET_GetRxFrame先获取元数据,减少无效操作
长帧(多 BD 拼接)ENET_GetRxFrame自动处理缓冲区关联关系
简单协议 / 直接解析数据ENET_ReadFrame一步完成拷贝,代码简洁
需要长期保存数据ENET_ReadFrame数据脱离硬件缓冲区生命周期
低吞吐量 / 低性能要求ENET_ReadFrame拷贝开销可忽略,开发效率高
http://www.dtcms.com/a/322106.html

相关文章:

  • MySQL 正则表达式详细说明
  • AI摄像头动捕:让动作分析更自由、更智能、更高效
  • 刚刚,GPT-5 炸裂登场!可免费使用
  • Word中怎样插入特殊符号
  • seo-使用nuxt定义页面标题和meta等信息
  • 11_Mybatis 是如何进行DO类和数据库字段的映射的?
  • HTTP/HTTPS代理,支持RSA和SM2算法
  • 消防通道占用识别误报率↓79%:陌讯动态区域感知算法实战解析
  • 自签名证书实现HTTPS协议
  • 17.14 CogVLM-17B多模态模型爆肝部署:4-bit量化+1120px高清输入,A100实战避坑指南
  • 登上Nature子刊,深度学习正逐渐接管基础模型
  • NY128NY133美光固态闪存NY139NY143
  • 智驭全球波动:跨境量化交易系统2025解决方案
  • Linux系统:Ext系列文件系统(硬件篇)
  • 专题二_滑动窗口_将x减到0的最小操作数
  • Dart 单例模式:工厂构造、静态变量与懒加载
  • 频谱图学习笔记
  • python 通过Serper API联网搜索并大模型整理内容
  • 软件测试面试常见问题【含答案】
  • EtherCAT WatchDog
  • V4L2摄像头采集 + WiFi实时传输实战全流程
  • 深圳市天正达电子股份有限公司参展AUTO TECH China 2025 广州国际汽车技术展览会
  • std::transform
  • AI大模型专题:LLM大模型(Prompt提示词工程)
  • C语言实现经典扫雷游戏全解析
  • 使用观测云打造企业级监控告警中心
  • cudagraph 本质详解
  • Vue框架进阶
  • 宠智灵打造宠物AI开放平台:精准识别、灵活部署、生态共建
  • C++入门(上) -- 讲解超详细