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

EtherCAT主站SOEM -- 2 -- SOEM之ethercatbase.h/c文件解析

EtherCAT主站SOEM -- 2 -- SOEM之ethercatbase.h/c文件解析

  • 一 ethercatbase.h/c文件功能预览:
  • 二 ethercatbase.h/c 文件的主要函数的作用:
    • 2.1 ecx_writedatagramdata:
    • 2.2 ecx_setupdatagram:
    • 2.3 ecx_adddatagram:
    • 2.4 分布式时钟同步 ecx_LRWDC 函数:
    • 2.5 函数(例如 ecx_BWR、ecx_BRD、ecx_APRD、ecx_ARMW 等):
  • 三 ethercatbase.c 原文件的中文注释
  • 该文档修改记录:
  • 总结

一 ethercatbase.h/c文件功能预览:

函数名称功能和用途使用场景
ecx_setupdatagram设置EtherCAT数据报文的头部信息,包括通信类型、索引、ADP、ADO、长度和数据。用于配置EtherCAT数据报文的头部信息,以便进行数据通信。
ecx_adddatagram向EtherCAT数据报文中添加数据段,包括通信类型、索引、更多标志、ADP、ADO、长度和数据。适用于逐步构建EtherCAT数据报文,可以添加多个数据段。
ecx_BWR向EtherCAT从站写入数据,指定ADP、ADO、长度和数据。用于将数据写入EtherCAT从站的寄存器或数据区域。
ecx_BRD从EtherCAT从站读取数据,指定ADP、ADO、长度和数据。用于从EtherCAT从站的寄存器或数据区域读取数据。
ecx_APRD从EtherCAT从站异步读取数据,指定ADP、ADO、长度和数据。用于异步读取EtherCAT从站的寄存器或数据区域数据。
ecx_ARMW从EtherCAT从站异步写入数据,指定ADP、ADO、长度和数据。用于异步写入数据到EtherCAT从站的寄存器或数据区域。
ecx_FRMW向EtherCAT从站发送帧数据,指定ADP、ADO、长度和数据。用于发送帧数据到EtherCAT从站。
ecx_APRDw从EtherCAT从站异步读取字数据,指定ADP和ADO。用于异步读取EtherCAT从站的字数据。
ecx_FPRD从EtherCAT从站快速读取数据,指定ADP、ADO、长度和数据。用于快速读取EtherCAT从站的数据。
ecx_FPRDw从EtherCAT从站快速读取字数据,指定ADP和ADO。用于快速读取EtherCAT从站的字数据。
ecx_APWRw向EtherCAT从站异步写入字数据,指定ADP、ADO和数据。用于异步写入字数据到EtherCAT从站。
ecx_APWR向EtherCAT从站写入数据,指定ADP、ADO、长度和数据。用于向EtherCAT从站的寄存器或数据区域写入数据。
ecx_FPWRw向EtherCAT从站快速写入字数据,指定ADP、ADO和数据。用于快速写入字数据到EtherCAT从站。
ecx_FPWR向EtherCAT从站快速写入数据,指定ADP、ADO、长度和数据。用于快速写入数据到EtherCAT从站。
ecx_LRW从EtherCAT从站的逻辑地址中读取数据,指定逻辑地址、长度和数据。用于从EtherCAT从站的逻辑地址读取数据。
ecx_LRD从EtherCAT从站的逻辑地址中读取字数据,指定逻辑地址和数据。用于从EtherCAT从站的逻辑地址读取字数据。
ecx_LWR向EtherCAT从站的逻辑地址中写入数据,指定逻辑地址、长度和数据。用于向EtherCAT从站的逻辑地址写入数据。
ecx_LRWDC从EtherCAT从站的逻辑地址中读取数据,包括数据校验和时序信息,指定逻辑地址、长度、数据、数据校验标志和时间信息。用于从EtherCAT从站的逻辑地址读取数据,同时获取数据的校验和时序信息。
ec_setupdatagram(适用于EC_VER1) 设置EtherCAT数据报文的头部信息,包括通信类型、索引、ADP、ADO、长度和数据。(适用于EC_VER1) 用于配置EtherCAT数据报文的头部信息,以便进行数据通信。
ec_adddatagram(适用于EC_VER1) 向EtherCAT数据报文中添加数据段,包括通信类型、索引、更多标志、ADP、ADO、长度和数据。(适用于EC_VER1) 适用于逐步构建EtherCAT数据报文,可以添加多个数据段。
ec_BWR(适用于EC_VER1) 向EtherCAT从站写入数据,指定ADP、ADO、长度和数据。(适用于EC_VER1) 用于将数据写入EtherCAT从站的寄存器或数据区域。
ec_BRD(适用于EC_VER1) 从EtherCAT从站读取数据,指定ADP、ADO、长度和数据。(适用于EC_VER1) 用于从EtherCAT从站的寄存器或数据区域读取数据。
                                                                                                                                                                 | ...                                                                                                          

二 ethercatbase.h/c 文件的主要函数的作用:

ethercatbase.h 文件包含了一系列数据结构、常量和函数声明,用于实现 EtherCAT 主站的核心功能。以下是一些可能包含在 ethercatbase.h 文件中的内容:

  • 数据结构:定义了用于管理 EtherCAT 主站的数据结构,包括主站状态、从站配置、数据对象映射等。

  • 常量:包含了一些与 EtherCAT 相关的常量,如 EtherCAT 数据帧的大小、标志位等。

  • 函数声明:定义了用于初始化、配置和管理 EtherCAT 主站的函数接口。

ethercatbase.c 文件包含了 SOEM 库中实际实现 EtherCAT 主站功能的代码。它包括了与 EtherCAT 通信相关的底层功能,以及用于初始化和配置 EtherCAT 主站的代码。以下是一些 ethercatbase.c 文件中可能包含的功能:

  • 初始化 EtherCAT 主站:包括初始化数据结构、配置网络接口等。

  • 从站配置:配置网络中的 EtherCAT 从站,包括分配地址、数据对象映射等。

  • 数据帧处理:处理来自 EtherCAT 从站的数据帧,以实现数据交换。

  • 周期性通信:根据配置的周期时间,发送和接收 EtherCAT 数据帧。

  • 状态管理:管理主站的状态,以确保网络正常运行。

总之,ethercatbase.h 和 ethercatbase.c 文件是 SOEM 库的核心部分,用于实现 EtherCAT 主站的基本功能,包括初始化、配置、数据交换和状态管理。

2.1 ecx_writedatagramdata:

这个函数用于向 EtherCAT 数据报中写入数据。它会根据提供的命令(Command)、长度(Length)和数据(Data)来填充数据报的数据部分。这是在 EtherCAT 主站发送数据给从站的过程中使用的函数。

2.2 ecx_setupdatagram:

该函数用于生成并设置 EtherCAT 数据报,这些数据报将包含在标准以太网帧中。您可以通过此函数指定命令、索引、地址位置、地址偏移、长度和数据等信息,以准备 EtherCAT 数据报。这是为了创建要发送到 EtherCAT 从站的命令和数据。

2.3 ecx_adddatagram:

这个函数用于将 EtherCAT 数据报添加到现有的以太网帧中,使得多个数据报可以连续发送到不同的 EtherCAT 从站。它有助于组装一个完整的以太网帧,包括多个 EtherCAT 数据报。

2.4 分布式时钟同步 ecx_LRWDC 函数:

类似于 ecx_LRW,但它还包括分布式时钟同步的处理。它在同一帧中发送两个数据报,一个用于 LRW 操作,另一个用于时钟分布,从而实现与参考从站的同步和获取分布式时钟时间。

2.5 函数(例如 ecx_BWR、ecx_BRD、ecx_APRD、ecx_ARMW 等):

这些函数实现了不同的 EtherCAT 数据传输原语,允许主站与从站进行数据读取和写入。它们涉及广播命令和指定地址位置和偏移来进行数据交互。

总的来说,ethercatbase.c 中的函数提供了与 EtherCAT 从站进行通信所需的基本功能。这些函数允许 EtherCAT 主站配置数据报、发送命令和数据,以及处理从站的响应。SOEM 库的 ethercatbase.c 文件是构建自定义 EtherCAT 主站应用程序的重要组成部分。

三 ethercatbase.c 原文件的中文注释

/** 根据GNU通用公共许可证第2版(附有例外情况)授权。请参阅* 项目根目录中的LICENSE文件以获取完整的许可信息*//** \file* \brief* 基本EtherCAT功能。** 在以太网帧中设置数据报。* EtherCAT数据报原语,广播,自动增量,配置和* 逻辑寻址数据传输。所有基本传输都是阻塞的,因此* 等待帧被返回给主站或超时。如果这不可接受,可以构建您自己的数据报* 并使用nicdrv.c中的函数。*/#include <stdio.h>
#include <string.h>
#include "oshw.h"
#include "osal.h"
#include "ethercattype.h"
#include "ethercatbase.h"/** 将数据写入EtherCAT数据报。** @param[out] datagramdata   = 数据报的数据部分* @param[in]  com            = 命令* @param[in]  length         = 数据缓冲区的长度* @param[in]  data           = 要复制到数据报中的数据缓冲区*/
static void ecx_writedatagramdata(void *datagramdata, ec_cmdtype com, uint16 length, const void * data)
{if (length > 0){switch (com){case EC_CMD_NOP:/* 没有操作。 *//* 没有操作。初始化数据,以使帧处于已知状态。 */memset(datagramdata, 0, length);break;default:memcpy(datagramdata, data, length);break;}}
}/** 生成并设置标准以太网帧中的EtherCAT数据报。** @param[in] port        = 端口上下文结构* @param[out] frame       = 帧缓冲区* @param[in]  com         = 命令* @param[in]  idx         = 用于TX和RX缓冲区的索引* @param[in]  ADP         = 地址位置* @param[in]  ADO         = 地址偏移* @param[in]  length      = 数据报的长度,不包括EtherCAT头部* @param[in]  data        = 要复制到数据报中的数据缓冲区* @return 始终为0*/
int ecx_setupdatagram(ecx_portt *port, void *frame, uint8 com, uint8 idx, uint16 ADP, uint16 ADO, uint16 length, void *data)
{ec_comt *datagramP;uint8 *frameP;frameP = frame;/* 以太网头部已经在帧缓冲区中预设和固定需要在此之后添加EtherCAT头部 */datagramP = (ec_comt*)&frameP[ETH_HEADERSIZE];datagramP->elength = htoes(EC_ECATTYPE + EC_HEADERSIZE + length);datagramP->command = com;datagramP->index = idx;datagramP->ADP = htoes(ADP);datagramP->ADO = htoes(ADO);datagramP->dlength = htoes(length);ecx_writedatagramdata(&frameP[ETH_HEADERSIZE + EC_HEADERSIZE], com, length, data);/* 将WKC设置为零 */frameP[ETH_HEADERSIZE + EC_HEADERSIZE + length] = 0x00;frameP[ETH_HEADERSIZE + EC_HEADERSIZE + length + 1] = 0x00;/* 在缓冲区数组中设置帧的大小 */port->txbuflength[idx] = ETH_HEADERSIZE + EC_HEADERSIZE + EC_WKCSIZE + length;return 0;
}/** 将EtherCAT数据报添加到带有现有数据报的标准以太网帧中。** @param[in] port        = 端口上下文结构* @param[out] frame      = 帧缓冲区* @param[in] com        = 命令* @param[in] idx        = 用于TX和RX缓冲区的索引* @param[in] more       = 如果后续还有更多数据报,则为TRUE* @param[in] ADP        = 地址位置* @param[in] ADO        = 地址偏移* @param[in] length     = 数据报长度,不包括EtherCAT头* @param[in] data       = 要复制到数据报中的数据缓冲区* @return RX帧中数据的偏移,用于在RX后检索数据。*/
uint16 ecx_adddatagram(ecx_portt *port, void *frame, uint8 com, uint8 idx, boolean more, uint16 ADP, uint16 ADO, uint16 length, void *data)
{ec_comt *datagramP;uint8 *frameP;uint16 prevlength;frameP = frame;/* 复制以前的帧大小 */prevlength = (uint16)port->txbuflength[idx];datagramP = (ec_comt*)&frameP[ETH_HEADERSIZE];/* 将新数据报添加到以太网帧大小中 */datagramP->elength = htoes( etohs(datagramP->elength) + EC_HEADERSIZE + length );/* 将“数据报跟随”标志添加到以前子帧dlength */datagramP->dlength = htoes( etohs(datagramP->dlength) | EC_DATAGRAMFOLLOWS );/* 设置新的EtherCAT头位置 */datagramP = (ec_comt*)&frameP[prevlength - EC_ELENGTHSIZE];datagramP->command = com;datagramP->index = idx;datagramP->ADP = htoes(ADP);datagramP->ADO = htoes(ADO);if (more){/* 这不是要添加的最后一个数据报 */datagramP->dlength = htoes(length | EC_DATAGRAMFOLLOWS);}else{/* 这是帧中的最后一个数据报 */datagramP->dlength = htoes(length);}ecx_writedatagramdata(&frameP[prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE], com, length, data);/* 将WKC设置为零 */frameP[prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE + length] = 0x00;frameP[prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE + length + 1] = 0x00;/* 在缓冲区数组中设置帧的大小 */port->txbuflength[idx] = prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE + EC_WKCSIZE + length;/* 返回RX帧中数据的偏移由于以太网头的去除,比tx帧小14字节 */return prevlength + EC_HEADERSIZE - EC_ELENGTHSIZE - ETH_HEADERSIZE;
}/** BRW "广播写入"原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in] ADP         = 地址位置,通常为0* @param[in] ADO         = 地址偏移,从属于内存地址* @param[in] length      = 数据缓冲区的长度* @param[in] data        = 要写入从属的数据缓冲区* @param[in] timeout     = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_BWR (ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{uint8 idx;int wkc;/* 获取新的索引 */idx = ecx_getindex (port);/* 设置数据报 */ecx_setupdatagram (port, &(port->txbuf[idx]), EC_CMD_BWR, idx, ADP, ADO, length, data);/* 发送数据并等待答复 */wkc = ecx_srconfirm (port, idx, timeout);/* 清除缓冲区状态 */ecx_setbufstat (port, idx, EC_BUF_EMPTY);return wkc;
}/** BRD "广播读取"原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in]  ADP        = 地址位置,通常为0* @param[in]  ADO        = 地址偏移,从属的内存地址* @param[in]  length     = 数据缓冲区的长度* @param[out] data       = 用于存放从属数据的数据缓冲区* @param[in]  timeout    = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_BRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{uint8 idx;int wkc;/* 获取新的索引 */idx = ecx_getindex(port);/* 设置数据报 */ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_BRD, idx, ADP, ADO, length, data);/* 发送数据并等待答复 */wkc = ecx_srconfirm (port, idx, timeout);if (wkc > 0){/* 复制数据报到数据缓冲区 */memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);}/* 清除缓冲区状态 */ecx_setbufstat(port, idx, EC_BUF_EMPTY);return wkc;
}/** APRD "自动增量地址读取"原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in]  ADP        = 地址位置,每个从属++,具有0的从属执行* @param[in]  ADO        = 地址偏移,从属内存地址* @param[in]  length     = 数据缓冲区的长度* @param[out] data       = 用于存放从属数据的数据缓冲区* @param[in]  timeout    = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_APRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{int wkc;uint8 idx;idx = ecx_getindex(port);ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_APRD, idx, ADP, ADO, length, data);wkc = ecx_srconfirm(port, idx, timeout);if (wkc > 0){memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);}ecx_setbufstat(port, idx, EC_BUF_EMPTY);return wkc;
}/** APRMW "自动增量地址读取,多次写入"原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in]  ADP        = 地址位置,每个从属++,具有0的从属执行读取,随后的从属执行写入。* @param[in]  ADO        = 地址偏移,从属内存地址* @param[in]  length     = 数据缓冲区的长度* @param[out] data       = 用于存放从属数据的数据缓冲区* @param[in]  timeout    = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_ARMW(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{int wkc;uint8 idx;idx = ecx_getindex(port);ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_ARMW, idx, ADP, ADO, length, data);wkc = ecx_srconfirm(port, idx, timeout);if (wkc > 0){memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);}ecx_setbufstat(port, idx, EC_BUF_EMPTY);return wkc;
}/** FPRMW "配置地址读取,多次写入"原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in]  ADP        = 地址位置,具有地址的从属执行读取,随后的从属执行写入。* @param[in]  ADO        = 地址偏移,从属内存地址* @param[in]  length     = 数据缓冲区的长度* @param[out] data       = 用于存放从属数据的数据缓冲区* @param[in]  timeout    = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_FRMW(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{int wkc;uint8 idx;idx = ecx_getindex(port);ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_FRMW, idx, ADP, ADO, length, data);wkc = ecx_srconfirm(port, idx, timeout);if (wkc > 0){memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);}ecx_setbufstat(port, idx, EC_BUF_EMPTY);return wkc;
}/** APRDw "自动增量地址读取" 字返回原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in] ADP         = 地址位置,每个从属++,具有0的从属执行读取。* @param[in] ADO         = 地址偏移,从属内存地址* @param[in] timeout     = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 从从属获取的字数据*/
uint16 ecx_APRDw(ecx_portt *port, uint16 ADP, uint16 ADO, int timeout)
{uint16 w;w = 0;ecx_APRD(port, ADP, ADO, sizeof(w), &w, timeout);return w;
}/** FPRD "配置地址读取"原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in]  ADP        = 地址位置,具有地址的从属执行读取。* @param[in]  ADO        = 地址偏移,从属内存地址* @param[in]  length     = 数据缓冲区的长度* @param[out] data       = 用于存放从属数据的数据缓冲区* @param[in]  timeout    = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_FPRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{int wkc;uint8 idx;idx = ecx_getindex(port);ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_FPRD, idx, ADP, ADO, length, data);wkc = ecx_srconfirm(port, idx, timeout);if (wkc > 0){memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);}ecx_setbufstat(port, idx, EC_BUF_EMPTY);return wkc;
}/** FPRDw "配置地址读取" 字返回原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in] ADP         = 地址位置,具有地址的从属执行读取。* @param[in] ADO         = 地址偏移,从属内存地址* @param[in] timeout     = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 从从属获取的字数据*/
uint16 ecx_FPRDw(ecx_portt *port, uint16 ADP, uint16 ADO, int timeout)
{uint16 w;w = 0;ecx_FPRD(port, ADP, ADO, sizeof(w), &w, timeout);return w;
}/** APWR "自动增量地址写入"原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in] ADP         = 地址位置,每个从属++,具有0的从属执行写入。* @param[in] ADO         = 地址偏移,从属内存地址* @param[in] length      = 数据缓冲区的长度* @param[in] data        = 要写入从属的数据缓冲区* @param[in] timeout     = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_APWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{uint8 idx;int wkc;idx = ecx_getindex(port);ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_APWR, idx, ADP, ADO, length, data);wkc = ecx_srconfirm(port, idx, timeout);ecx_setbufstat(port, idx, EC_BUF_EMPTY);return wkc;
}/** APWRw "自动增量地址写入"字原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in] ADP         = 地址位置,每个从属++,具有0的从属执行写入。* @param[in] ADO         = 地址偏移,从属内存地址* @param[in] data        = 要写入从属的字数据* @param[in] timeout     = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_APWRw(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout)
{return ecx_APWR(port, ADP, ADO, sizeof(data), &data, timeout);
}/** FPWR "配置地址写入"原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in] ADP         = 地址位置,具有地址的从属执行写入。* @param[in] ADO         = 地址偏移,从属内存地址* @param[in] length      = 数据缓冲区的长度* @param[in] data        = 要写入从属的数据缓冲区* @param[in] timeout     = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_FPWR(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{int wkc;uint8 idx;idx = ecx_getindex(port);ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_FPWR, idx, ADP, ADO, length, data);wkc = ecx_srconfirm(port, idx, timeout);ecx_setbufstat(port, idx, EC_BUF_EMPTY);return wkc;
}/** FPWR "配置地址写入"原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in] ADP         = 地址位置,具有地址的从属执行写入。* @param[in] ADO         = 地址偏移,从属内存地址* @param[in] data        = 要写入从属的字数据* @param[in] timeout     = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_FPWRw(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 data, int timeout)
{return ecx_FPWR(port, ADP, ADO, sizeof(data), &data, timeout);
}/** LRW "逻辑内存读/写"原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in]     LogAdr  = 逻辑内存地址* @param[in]     length  = 数据缓冲区的长度* @param[in,out] data    = 用于写入和从从属读取数据的数据缓冲区* @param[in]     timeout = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_LRW(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout)
{uint8 idx;int wkc;idx = ecx_getindex(port);ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_LRW, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data);wkc = ecx_srconfirm(port, idx, timeout);if ((wkc > 0) && (port->rxbuf[idx][EC_CMDOFFSET] == EC_CMD_LRW)){memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);}ecx_setbufstat(port, idx, EC_BUF_EMPTY);return wkc;
}/** LRD "逻辑内存读取"原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in]  LogAdr     = 逻辑内存地址* @param[in]  length     = 从从属读取的字节数* @param[out] data       = 从从属读取的数据的数据缓冲区* @param[in]  timeout    = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_LRD(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout)
{uint8 idx;int wkc;idx = ecx_getindex(port);ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_LRD, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data);wkc = ecx_srconfirm(port, idx, timeout);if ((wkc > 0) && (port->rxbuf[idx][EC_CMDOFFSET] == EC_CMD_LRD)){memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);}ecx_setbufstat(port, idx, EC_BUF_EMPTY);return wkc;
}/** LWR "逻辑内存写入"原语。阻塞。** @param[in] port        = 端口上下文结构* @param[in] LogAdr      = 逻辑内存地址* @param[in] length      = 数据缓冲区的长度* @param[in] data        = 要写入从属的数据缓冲区* @param[in] timeout     = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_LWR(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, int timeout)
{uint8 idx;int wkc;idx = ecx_getindex(port);ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_LWR, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data);wkc = ecx_srconfirm(port, idx, timeout);ecx_setbufstat(port, idx, EC_BUF_EMPTY);return wkc;
}/** LRW "逻辑内存读/写"原语加时钟分发。阻塞。* 帧由两个数据报组成,一个是LRW,一个是FPRMW。** @param[in] port        = 端口上下文结构* @param[in]     LogAdr  = 逻辑内存地址* @param[in]     length  = 数据缓冲区的长度* @param[in,out] data    = 用于写入和从从属读取数据的数据缓冲区* @param[in]     DCrs    = 分布式时钟参考从属地址* @param[out]    DCtime  = 从参考从属读取的DC时间* @param[in]     timeout = 超时时间(以微秒为单位),标准值为EC_TIMEOUTRET* @return 工作计数器或EC_NOFRAME*/
int ecx_LRWDC(ecx_portt *port, uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout)
{uint16 DCtO;uint8 idx;int wkc;uint64 DCtE;idx = ecx_getindex(port);/* 第一个数据报是LRW */ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_LRW, idx, LO_WORD(LogAdr), HI_WORD(LogAdr), length, data);/* 第二个数据报是FPRMW */DCtE = htoell(*DCtime);DCtO = ecx_adddatagram(port, &(port->txbuf[idx]), EC_CMD_FRMW, idx, FALSE, DCrs, ECT_REG_DCSYSTIME, sizeof(DCtime), &DCtE);wkc = ecx_srconfirm(port, idx, timeout);if ((wkc > 0) && (port->rxbuf[idx][EC_CMDOFFSET] == EC_CMD_LRW)){memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);memcpy(&wkc, &(port->rxbuf[idx][EC_HEADERSIZE + length]), EC_WKCSIZE);memcpy(&DCtE, &(port->rxbuf[idx][DCtO]), sizeof(*DCtime));*DCtime = etohll(DCtE);}ecx_setbufstat(port, idx, EC_BUF_EMPTY);return wkc;
}#ifdef EC_VER1
int ec_setupdatagram(void *frame, uint8 com, uint8 idx, uint16 ADP, uint16 ADO, uint16 length, void *data)
{return ecx_setupdatagram (&ecx_port, frame, com, idx, ADP, ADO, length, data);
}uint16 ec_adddatagram (void *frame, uint8 com, uint8 idx, boolean more, uint16 ADP, uint16 ADO, uint16 length, void *data)
{return ecx_adddatagram (&ecx_port, frame, com, idx, more, ADP, ADO, length, data);
}int ec_BWR(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{return ecx_BWR (&ecx_port, ADP, ADO, length, data, timeout);
}int ec_BRD(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{return ecx_BRD(&ecx_port, ADP, ADO, length, data, timeout);
}int ec_APRD(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{return ecx_APRD(&ecx_port, ADP, ADO, length, data, timeout);
}int ec_ARMW(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{return ecx_ARMW(&ecx_port, ADP, ADO, length, data, timeout);
}int ec_FRMW(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{return ecx_FRMW(&ecx_port, ADP, ADO, length, data, timeout);
}uint16 ec_APRDw(uint16 ADP, uint16 ADO, int timeout)
{uint16 w;w = 0;ec_APRD(ADP, ADO, sizeof(w), &w, timeout);return w;
}int ec_FPRD(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{return ecx_FPRD(&ecx_port, ADP, ADO, length, data, timeout);
}uint16 ec_FPRDw(uint16 ADP, uint16 ADO, int timeout)
{uint16 w;w = 0;ec_FPRD(ADP, ADO, sizeof(w), &w, timeout);return w;
}int ec_APWR(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{return ecx_APWR(&ecx_port, ADP, ADO, length, data, timeout);
}int ec_APWRw(uint16 ADP, uint16 ADO, uint16 data, int timeout)
{return ec_APWR(ADP, ADO, sizeof(data), &data, timeout);
}int ec_FPWR(uint16 ADP, uint16 ADO, uint16 length, void *data, int timeout)
{return ecx_FPWR(&ecx_port, ADP, ADO, length, data, timeout);
}int ec_FPWRw(uint16 ADP, uint16 ADO, uint16 data, int timeout)
{return ec_FPWR(ADP, ADO, sizeof(data), &data, timeout);
}int ec_LRW(uint32 LogAdr, uint16 length, void *data, int timeout)
{return ecx_LRW(&ecx_port, LogAdr, length, data, timeout);
}int ec_LRD(uint32 LogAdr, uint16 length, void *data, int timeout)
{return ecx_LRD(&ecx_port, LogAdr, length, data, timeout);
}int ec_LWR(uint32 LogAdr, uint16 length, void *data, int timeout)
{return ecx_LWR(&ecx_port, LogAdr, length, data, timeout);
}int ec_LRWDC(uint32 LogAdr, uint16 length, void *data, uint16 DCrs, int64 *DCtime, int timeout)
{return ecx_LRWDC(&ecx_port, LogAdr, length, data, DCrs, DCtime, timeout);
}
#endif

该文档修改记录:

修改时间修改说明
2023年11月3日EtherCAT主站SOEM – 2 – SOEM之ethercatbase.h/c文件解析

总结

以上就是EtherCAT主站SOEM – 2 – SOEM之ethercatbase.h/c文件解析的内容。
有不明白的地方欢迎留言;有建议欢迎留言,我后面编写文档好改进。
创作不容,如果文档对您有帮助,记得给个赞。

相关文章:

EtherCAT主站SOEM -- 2 -- SOEM之ethercatbase.h/c文件解析

EtherCAT主站SOEM -- 2 -- SOEM之ethercatbase.h/c文件解析 一 ethercatbase.h/c文件功能预览&#xff1a;二 ethercatbase.h/c 文件的主要函数的作用&#xff1a;2.1 ecx_writedatagramdata&#xff1a;2.2 ecx_setupdatagram&#xff1a;2.3 ecx_adddatagram&#xff1a;2.4 …...

Spring集成高性能队列Disruptor

Disruptor简介 Disruptor&#xff08;中文翻译为“破坏者”或“颠覆者”&#xff09;是一种高性能、低延迟的并发编程框架&#xff0c;最初由LMAX Exchange开发。它的主要目标是解决在金融交易系统等需要高吞吐量和低延迟的应用中的并发问题。 Disruptor特点 无锁并发&#x…...

C++——类和对象(中)完结

赋值运算符重载 运算符重载 C 为了增强代码的可读性引入了运算符重载 &#xff0c; 运算符重载是具有特殊函数名的函数 &#xff0c;也具有其 返回值类型&#xff0c;函数名字以及参数列表&#xff0c;其返回值类型与参数列表与普通的函数类似。 函数名字为&#xff1a;关键…...

Sqoop的安装和使用

目录 一.安装 二.导入 1.全量导入 一.MySQL导入HDFS 二.MySQL导入Hive 2.增量导入 一.过滤导入hdfs/hive 二.导出 一.安装 1.下载地址&#xff1a;sqoop下载地址 2.解压 tar -zxvf ./sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz -C ../module/ 3.改名和配置归属权限 #改名…...

java毕业设计基于springboot+vue的村委会管理系统

项目介绍 采用JAVA语言&#xff0c;结合SpringBoot框架与Vue框架以及MYSQL数据库设计并实现的。本村委会管理系统主要包括个人中心、村民管理、村委会管理、村民信息管理、土地变更管理、农业补贴管理、党员信息管理等多个模块。它帮助村委会管理实现了信息化、网络化&#xf…...

【C++】多态 ⑪ ( 纯虚函数和抽象类 | 纯虚函数语法 | 抽象类和实现 | 代码示例 )

文章目录 一、纯虚函数和抽象类1、纯虚函数2、纯虚函数语法3、抽象类和实现 二、完整代码示例 一、纯虚函数和抽象类 1、纯虚函数 纯虚函数 : 在 C 语言中 , " 纯虚函数 " 是 特殊类型的 虚函数 , " 纯虚函数 " 在 父类 中 声明 , 但是没有实现 ; 抽象类 …...

node 第十四天 基于express的第三方中间件multer node后端处理用户上传文件

Multer 是一个 node.js 中间件&#xff0c;用于处理multipart/form-data 类型的表单数据&#xff0c;它主要用于上传文件。它是写在 busboy 之上的所以非常高效。前面我们已经知道了怎样利用express提供的静态资源处理中间件express.static()处理用户请求静态资源文件(图片, js…...

KnowledgeGPT:利用检索和存储访问知识库上增强大型语言模型10.30

利用检索和存储访问知识库上增强大型语言模型 摘要引言2 相关研究3方法3.1 任务定义3.2 知识检索3.2.1 代码实现3.2.2 实体链接3.2.3 获取实体信息3.2.4 查找实体或值3.2.5 查找关系 3.3 知识存储 4 实验4.1 实验设置4.2 流行知识库上的查询4.3 基于知识的问题回答 摘要 大型语…...

Angular material Chips Autocomplete

Chips Autocomplete 官网的例子我没法正常使用&#xff0c;无法实现搜索 我的select是个通用组件&#xff0c;现在贴代码&#xff1a; component.ts import {Component,ElementRef,forwardRef,Input,OnChanges,OnDestroy,OnInit,SimpleChanges,ViewChild, } from angular/co…...

『亚马逊云科技产品测评』活动征文|搭建基础运维环境

授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 目录 1、什么是容器化部署 2、连接到控制台 3、安装docker 3.1 更新…...

双指针扫描

import os import sys# 请在此输入您的代码 sinput() Alist(s) nlen(A) t1 for i in range(n//2):if A[i]!A[n-1-i]:t0break if t1:print(Y) else:print(N)n,smap(int,input().split()) alist(map(int,input().split())) #尺取法&#xff0c;变O(n*n)为O(n) #维护一个最短的区间…...

uniapp小程序九宫格抽奖

定义好奖品下标&#xff0c;计时器开始抽奖&#xff0c;请求接口&#xff0c;出现中奖奖品之后&#xff0c;获取中奖商品对应的奖品下标&#xff0c;再次计时器判断当前移动的小标是否为中奖商品的下标&#xff0c;并且是否转到3圈&#xff08;防止转1圈就停止&#xff09;&…...

mysql树状结构查询及注意事项

一、说明 由于Mysql不像oracle一样支持树状查询&#xff0c;需要用户自行处理&#xff0c;本文记录了一种常见的通过自定义函数的方式进行mysql树状查询的方法&#xff0c;以及使用的注意事项。 二、函数 CREATE DEFINERrootlocalhost FUNCTION get_child_menus(in_pid varc…...

TimeGPT-1——第一个时间序列数据领域的大模型他来了

一直有一个问题:时间序列的基础模型能像自然语言处理那样存在吗?一个预先训练了大量时间序列数据的大型模型&#xff0c;是否有可能在未见过的数据上产生准确的预测?最近刚刚发表的一篇论文&#xff0c;Azul Garza和Max Mergenthaler-Canseco提出的TimeGPT-1&#xff0c;将ll…...

通过Google搜索广告传送的携带木马的PyCharm软件版本

导语 最近&#xff0c;一起新的恶意广告活动被发现&#xff0c;利用被入侵的网站通过Google搜索结果推广虚假版本的PyCharm软件。这个活动利用了动态搜索广告&#xff0c;将广告链接指向被黑客篡改的网页&#xff0c;用户点击链接后下载的并不是PyCharm软件&#xff0c;而是多种…...

网站文章收录因素,别人复制文章排名比你原创的好?

我经常看到有站长抱怨“网站不收录”&#xff0c;“排名不好”&#xff0c;“复制的文章为什么秒收”之类的问题。对于SEO从业者来说&#xff0c;这确实是一个打击&#xff0c;认为搜索引擎不公平。凭什么自己原创不收录&#xff0c;别人复制去了&#xff0c;秒收他的&#xff…...

C#开源的一个能利用Windows通知栏背单词的软件 - ToastFish

前言 今天给大家推荐一个C#开源且免费的能利用Windows通知栏背单词的软件&#xff0c;可以让你在上班、上课等恶劣环境下安全隐蔽地背单词&#xff08;利用摸鱼时间背单词的软件&#xff09;&#xff1a;ToastFish。 操作系统要求 目前该软件只支持Windows10及以上系统&…...

速拿offer,超全自动化测试面试题+答案汇总,背完还怕拿不到offer?

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、你会封装自动化…...

LeetCode----1415. 长度为 n 的开心字符串中字典序第 k 小的字符串

题目 一个 「开心字符串」定义为: 仅包含小写字母 [‘a’, ‘b’, ‘c’].对所有在 1 到 s.length - 1 之间的 i ,满足 s[i] != s[i + 1] (字符串的下标从 1 开始)。比方说,字符串 “abc”,“ac”,“b” 和 “abcbabcbcb” 都是开心字符串,但是 “aa”,“baa” 和 “a…...

2310C++协程超传服务器

原文 告别异步回调模型,写代码更简单.同样也是跨平台,仅头文件的,包含头文件即可用,来看看它的用法. 基本用法 提供getpost服务 coro_http_server server(1, 9001);server.set_http_handler<GET, POST>("/", [](coro_http_request &req, coro_http_respo…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...