SOEM源码解析——ec_init(初始化单网卡主站)

0 工具准备

1.SOEM-master-1.4.0源码

1 ec_init总览

/** Initialise lib in single NIC mode:初始化库在单网卡模式
 * @param[in] ifname   = Dev name, f.e. "eth0" 设备名
 * @return >0 if OK
 * @see ecx_init
 */
int ec_init(const char * ifname)
{
   return ecx_init(&ecx_context, ifname);
}
/** Initialise lib in single NIC mode:初始化库在单网卡模式
 * @param[in]  context = context struct SOEM句柄
 * @param[in] ifname   = Dev name, f.e. "eth0" 设备名
 * @return >0 if OK
 */
int ecx_init(ecx_contextt *context, const char * ifname)
{
   return ecx_setupnic(context->port, ifname, FALSE);
}

当我们的主站工作模式为单网卡而非冗余模式时会使用ec_init函数初始化SOEM库,ec_init函数是主站初始化时第一个执行的函数。它真正调用的是ecx_setupnic函数,该函数具体操作如下:

/** Basic setup to connect NIC to socket.
 * @param[in] port        = port context struct
 * @param[in] ifname      = Name of NIC device, f.e. "eth0"
 * @param[in] secondary   = if >0 then use secondary stack instead of primary
 * @return >0 if succeeded
 */
int ecx_setupnic(ecx_portt *port, const char *ifname, int secondary) 
{
   int i;
   int *psock;
     
   if (secondary)
   {
      /* secondary port stuct available? */
      /* 冗余端口结构体有效? */
      if (port->redport)
      {
         /* when using secondary socket it is automatically a redundant setup */
         /* 当使用冗余套接字时,切换到冗余状态*/
         psock = &(port->redport->sockhandle);
         *psock = -1;
         port->redstate                   = ECT_RED_DOUBLE;
         port->redport->stack.sock        = &(port->redport->sockhandle);
         port->redport->stack.txbuf       = &(port->txbuf);
         port->redport->stack.txbuflength = &(port->txbuflength);
         port->redport->stack.tempbuf     = &(port->redport->tempinbuf);
         port->redport->stack.rxbuf       = &(port->redport->rxbuf);
         port->redport->stack.rxbufstat   = &(port->redport->rxbufstat);
         port->redport->stack.rxsa        = &(port->redport->rxsa);
         ecx_clear_rxbufstat(&(port->redport->rxbufstat[0]));
      }
      else
      {
         /* fail */
         return 0;
      }
   }
   else
   {
      port->sockhandle        = -1;
      port->lastidx           = 0;
      port->redstate          = ECT_RED_NONE;
      port->stack.sock        = &(port->sockhandle);
      port->stack.txbuf       = &(port->txbuf);
      port->stack.txbuflength = &(port->txbuflength);
      port->stack.tempbuf     = &(port->tempinbuf);
      port->stack.rxbuf       = &(port->rxbuf);
      port->stack.rxbufstat   = &(port->rxbufstat);
      port->stack.rxsa        = &(port->rxsa);
      ecx_clear_rxbufstat(&(port->rxbufstat[0]));
      psock = &(port->sockhandle);
   }  

   /* setup ethernet headers in tx buffers so we don't have to repeat it */
   /* 在tx buffers里设置以太网帧头,这样就不必重复设置了 */
   for (i = 0; i < EC_MAXBUF; i++)
   {
      ec_setupheader(&(port->txbuf[i]));
      port->rxbufstat[i] = EC_BUF_EMPTY;
   }
   ec_setupheader(&(port->txbuf2));

   return 1;
}

该函数的功能可以分为2块:
(1)根据传进来的secondary分别设置传入句柄的普通端口或冗余端口,当secondary为FALSE也就是0时设置普通端口,当secondary为TRUE也就是1时设置冗余端口。
(2)设置发送缓冲区的以太网帧头,在后续的报文发送中就不必重复设置了。
上面的(1)、(2)步骤中涉及到ecx_clear_rxbufstat和ec_setupheader这2个函数,下面一起来看看它们的具体工作。

2 ecx_clear_rxbufstat函数解析

/**
 * @brief 将接收缓冲区状态设置为EC_BUF_EMPTY(空)
 * @param rxbufstat 接收缓冲区状态
 */
static void ecx_clear_rxbufstat(int *rxbufstat)
{
   int i;
   for(i = 0; i < EC_MAXBUF; i++)
   {
      rxbufstat[i] = EC_BUF_EMPTY;
   }
}

该函数主要工作就是将主站接收缓冲区所有buffer的状态设置为EC_BUF_EMPTY,也就是空,初始化接收缓冲区状态到正确的状态以便于后面的正常工作。

3 ec_setupheader函数解析

/** Fill buffer with ethernet header structure. 将以太网帧头填充到buffer
 * Destination MAC is allways broadcast. 目的mac地址是广播mac地址
 * Ethertype is allways ETH_P_ECAT. 帧类型是ETH_P_ECAT(0x88A4)
 * @param[out] p = buffer
 */
void ec_setupheader(void *p) 
{
   ec_etherheadert *bp;
   bp = p;
   bp->da0 = oshw_htons(0xffff);
   bp->da1 = oshw_htons(0xffff);
   bp->da2 = oshw_htons(0xffff);
   bp->sa0 = oshw_htons(priMAC[0]);
   bp->sa1 = oshw_htons(priMAC[1]);
   bp->sa2 = oshw_htons(priMAC[2]);
   bp->etype = oshw_htons(ETH_P_ECAT);
}

前面的ecx_clear_rxbufstat函数是为了设置接收缓冲区到争取的状态,这个函数则是为了设置发送缓冲区。
我们都知道,EtherCAT报文组成框图如下:
在这里插入图片描述
其中目的地址、源地址都可以设置为固定值,SOEM主站将目的地址设置为ff:ff:ff:ff:ff:ff、源地址设置为01:01:01:01:01:01、帧类型规定为0x88A4。SOEM主站这样设置以后便不需要每次组帧时设置以太网帧头,可以提高组帧效率。
还有一个地方需要特别注意,就是oshw_htons函数,用于将主机序(小端)设置为网络序(大端)。

4 总结

(1)SOEM主站初始化以太网帧为广播帧,主站所连接的网络中所有设备都会接收到EtherCAT报文。
(2)SOEM主站支持冗余模式,设置时和单网卡主站不同。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

要讨个公道,要分辨真假

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

【redis面试题】数据持久化

文章目录 前言一、RDB 的概述RDB 的执行原理 二、AOF 的概述AOF 的特点 三、RDB 与 AOF 的区别 前言 跟着B站的黑马程序员学习面试题&#xff0c;目前是redis的第五个内容——数据持久化 课程传送门&#xff1a;redis——数据持久化 在 Redis 中&#xff0c;提供了两种数据持久…

windows mysql安装

1、首先去官网下载mysql安装包&#xff0c;官网地址&#xff1a;MySQL :: Download MySQL Community Server 2&#xff1a;把安装包放到你安装mysql的地方&#xff0c;然后进行解压缩&#xff0c;注意&#xff0c;解压后的mysql没有配置文件&#xff0c;我们需要创建配置文件 配…

C++17中std::any的使用

类sdk:any提供类型安全的容器来存储任何类型的单个值。通俗地说&#xff0c;std::any是一个容器&#xff0c;可以在其中存储任何值(或用户数据)&#xff0c;而无需担心类型安全。void*的功能有限&#xff0c;仅存储指针类型&#xff0c;被视为不安全模式。std::any可以被视为vo…

计算机组成与结构-计算机体系结构

计算机体系结构 指令系统 Flynn分类法 SISD&#xff08;单指令流单数据流&#xff09; 结构 控制部分&#xff1a;一个处理器&#xff1a;一个主存模块&#xff1a;一个 代表 单处理器系统 SIMD&#xff08;单指令流多数据流&#xff09; 结构 控制部分&#xff1a;一个处理…

【LeetCode刷题-链表】--876.链表的中间结点

876.链表的中间结点 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.val val; this.next next; }* }*…

linux笔记总结-基本命令

参考&#xff1a; 1.Linux 和Windows比 比较 &#xff08;了解&#xff09; 1. 记住一句经典的话&#xff1a;在 Linux 世界里&#xff0c;一切皆文件 2. Linux目录结构 /lib • 系统开机所需要最基本的动态连接共享库&#xff0c;其作用类似于Windows里的DLL文件。几 乎所有…

项目实战:通过axios加载水果库存系统的首页数据

1、创建静态页面 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><link rel"stylesheet" href"style/index.css"><script src"script/axios.mi…

手把手创建Android应用程序·案例程序分析

目录 1. Activity 组件 MainActivity 类 2.布局文件activity_main. xml 3.应用程序配置文件 AndroidManifest.xml 4. Android的应用程序组件 4.1 Activity——活动 4.2 Service——服务 4.3 Broadcast receiver——广播接收器 4.4 Content provider——内容提供者…

React 项目结构小结

React 项目结构小结 简单的记录一下目前 React 项目用的依赖和实现 摸索了大半年了大概构建一套用起来还算轻松的体系……&#xff1f;基本上应该是说可以应对大部分的项目了 使用的依赖 目前项目还在 refactoring 的阶段&#xff0c;所以乱得很&#xff0c;这里是新建一个…

【使用Python编写游戏辅助工具】第一篇:概述

引言 欢迎阅读本系列文章&#xff0c;本系列将带领读者朋友们使用Python来实现一个简单而有趣的游戏辅助工具。 写这个系列的缘由源自笔者玩了一款游戏。正巧&#xff0c;笔者对Python编程算是有一定的熟悉&#xff0c;且Python语言具备实现各种有趣功能的能力&#xff0c;因…

基于单片机的可穿戴个人健康监测仪-智能手环

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、方案的设计与论证2.1设计任务及要求2.2 模块技术和方法综述2.3 设计可能遇到的困难 二、 系统总体框架3.1 硬件设计 三 软件部分4.1 主程序流程框 四、 结论五、 文章目录 概要 近几年智能化的不断发展&#…

3000 台 Apache ActiveMQ 服务器易受 RCE 攻击

超过三千个暴露在互联网上的 Apache ActiveMQ 服务器容易受到最近披露的关键远程代码执行 (RCE) 漏洞的影响。 Apache ActiveMQ 是一个可扩展的开源消息代理&#xff0c;可促进客户端和服务器之间的通信&#xff0c;支持 Java 和各种跨语言客户端以及许多协议&#xff0c;包括…

HiveSQL中last_value函数的应用

一、背景 在以下数据中如何实现对每一个列按照更新时间取最新的非null值&#xff1f; 1 a a null 202301 202301 1 b b null null 202302 1 null c null null 202303 1 d null null null 202304如何实现…

Nginx的location优先级和重定向

Nginx的location有优先级级和匹配方式&#xff1a; 在http模块有server,在server模块才有location,location匹配的是uri /test /image 在一个server当中有多个location,如何来确定匹配哪个location。 Nginx的正则表达式&#xff1a; ^:字符串的起始位置 $:字符串的结束位…

Spring Boot 常见面试题

目录 1.Spring Boot 快速入门什么是 Spring Boot&#xff1f;有什么优点&#xff1f;Spring Boot 与 Spring MVC 有什么区别&#xff1f;Spring 与 Spring Boot 有什么关系&#xff1f;✨什么是 Spring Boot Starters?Spring Boot 支持哪些内嵌 Servlet 容器&#xff1f;如何设…

【Excel密码】四个方法,设置excel表格只读模式

Excel文件想要设置成只读模式&#xff0c;其实很简单&#xff0c;今天给大家分享四个excel设置只读模式的方法。 方法一&#xff1a;文件属性 右键点击文件&#xff0c;查看文件属性&#xff0c;在属性界面&#xff0c;勾选上只读属性就可以了。 方法二&#xff1a;始终以只读…

微信-Native支付(扫二维码支付)工具类 2023最新保姆教程

0、照着微信开发文档 取到证书、秘钥等 好几个key 1、获取商户号merchantId 账户中心->商户信息->微信支付商户号 3、获取商户证书序列号merchantSerialNumber 账户中心->API安全->API证书管理 5、获取appID 产品中心->AppID账号管理 1、这个链接教你获取各…

基于卷积神经网络的抗压强度预测,基于卷积神经网络的抗折强度预测

目录 背影 卷积神经网络CNN的原理 卷积神经网络CNN的定义 卷积神经网络CNN的神经元 卷积神经网络CNN的激活函数 卷积神经网络CNN的传递函数 卷积神经网络CNN抗压强度预测 完整代码:基于卷积神经网络的抗压强度和抗折强度预测,基于CNN的抗压强度和抗折强度预测(代码完整,数据…

CAN报文的信号和信号组传递的意义

CAN将数据发送到COM层&#xff0c;在这个过程中报文是如何传递的&#xff1f; 0x105指的是一帧CAN报文&#xff0c;信号组指的是一帧CAN报文里的所有数据&#xff0c;信号指的是一帧CAN报文里的每一个信号&#xff0c;PDU代表了一帧CAN报文&#xff0c;它由报文ID&#xff08;I…