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 
#include 
#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,c语言,SOEM,EtherCAT,ethercatbase文件,工业总线,经验分享,EtherCAT主站)