EtherCAT主站IGH-- 4 -- IGH之datagram_pair.h/c文件解析

EtherCAT主站IGH-- 4 -- IGH之datagram_pair.h/c文件解析

  • [0 预览](#0 预览)
  • [一 该文件功能](#一 该文件功能)
    • [`datagram_pair.c` 文件功能函数预览](#datagram_pair.c 文件功能函数预览)
  • [二 函数功能介绍](#二 函数功能介绍)
    • [`datagram_pair.c` 中主要函数的作用](#datagram_pair.c 中主要函数的作用)
        • [1. `ec_datagram_pair_init`](#1. ec_datagram_pair_init)
        • [2. `ec_datagram_pair_clear`](#2. ec_datagram_pair_clear)
        • [3. `ec_datagram_pair_process`](#3. ec_datagram_pair_process)
  • [三 h文件翻译](#三 h文件翻译)
  • [四 c文件翻译](#四 c文件翻译)
  • 该文档修改记录:
  • 总结

0 预览

一 该文件功能

该文件定义了 EtherCAT 数据报对的方法。EtherCAT 是一种实时以太网通信标准,广泛用于工业自动化控制系统。数据报对用于在 EtherCAT 主站和从站之间传输数据的成对数据报。文件中包含的数据报对方法涵盖了初始化、清理和处理接收到的数据等操作。

datagram_pair.c 文件功能函数预览

函数 功能和用途 使用场景
ec_datagram_pair_init 初始化 EtherCAT 数据报对。 在创建新的数据报对时调用。
ec_datagram_pair_clear 清理 EtherCAT 数据报对。 在数据报对不再使用时调用以释放资源。
ec_datagram_pair_process 处理接收到的数据,计算工作计数总和。 在需要处理接收到的数据并计算工作计数时调用。

二 函数功能介绍

datagram_pair.c 中主要函数的作用

1. ec_datagram_pair_init
c 复制代码
int ec_datagram_pair_init(
        ec_datagram_pair_t *pair, /**< Datagram pair. */
        ec_domain_t *domain, /**< Parent domain. */
        uint32_t logical_offset, /**< Logical offset. */
        uint8_t *data, /**< Data pointer. */
        size_t data_size, /**< Data size. */
        const unsigned int used[] /**< input/output use count. */
        )
{
    ec_device_index_t dev_idx;
    int ret;

    INIT_LIST_HEAD(&pair->list);
    pair->domain = domain;

    for (dev_idx = EC_DEVICE_MAIN;
            dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
        ec_datagram_init(&pair->datagrams[dev_idx]);
        snprintf(pair->datagrams[dev_idx].name,
                EC_DATAGRAM_NAME_SIZE, "domain%u-%u-%s", domain->index,
                logical_offset, ec_device_names[dev_idx != 0]);
        pair->datagrams[dev_idx].device_index = dev_idx;
    }

    pair->expected_working_counter = 0U;

    for (dev_idx = EC_DEVICE_BACKUP;
            dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
        /* backup datagrams have their own memory */
        ret = ec_datagram_prealloc(&pair->datagrams[dev_idx], data_size);
        if (ret) {
            goto out_datagrams;
        }
    }

#if EC_MAX_NUM_DEVICES > 1
    if (!(pair->send_buffer = kmalloc(data_size, GFP_KERNEL))) {
        EC_MASTER_ERR(domain->master,
                "Failed to allocate domain send buffer!\n");
        ret = -ENOMEM;
        goto out_datagrams;
    }
#endif

    /* The ec_datagram_lxx() calls below can not fail, because either the
     * datagram has external memory or it is preallocated. */

    if (used[EC_DIR_OUTPUT] && used[EC_DIR_INPUT]) { // inputs and outputs
        ec_datagram_lrw_ext(&pair->datagrams[EC_DEVICE_MAIN],
                logical_offset, data_size, data);

        for (dev_idx = EC_DEVICE_BACKUP;
                dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
            ec_datagram_lrw(&pair->datagrams[dev_idx],
                    logical_offset, data_size);
        }

        // If LRW is used, output FMMUs increment the working counter by 2,
        // while input FMMUs increment it by 1.
        pair->expected_working_counter =
            used[EC_DIR_OUTPUT] * 2 + used[EC_DIR_INPUT];
    } else if (used[EC_DIR_OUTPUT]) { // outputs only
        ec_datagram_lwr_ext(&pair->datagrams[EC_DEVICE_MAIN],
                logical_offset, data_size, data);
        for (dev_idx = EC_DEVICE_BACKUP;
                dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
            ec_datagram_lwr(&pair->datagrams[dev_idx],
                    logical_offset, data_size);
        }

        pair->expected_working_counter = used[EC_DIR_OUTPUT];
    } else { // inputs only (or nothing)
        ec_datagram_lrd_ext(&pair->datagrams[EC_DEVICE_MAIN],
                logical_offset, data_size, data);
        for (dev_idx = EC_DEVICE_BACKUP;
                dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
            ec_datagram_lrd(&pair->datagrams[dev_idx], logical_offset,
                    data_size);
        }

        pair->expected_working_counter = used[EC_DIR_INPUT];
    }

    for (dev_idx = EC_DEVICE_MAIN;
            dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
        ec_datagram_zero(&pair->datagrams[dev_idx]);
    }

    return 0;

out_datagrams:
    for (dev_idx = EC_DEVICE_MAIN;
            dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
        ec_datagram_clear(&pair->datagrams[dev_idx]);
    }

    return ret;
}
  • 功能和用途:初始化 EtherCAT 数据报对。
  • 使用场景:在创建新的数据报对时调用。
2. ec_datagram_pair_clear
c 复制代码
void ec_datagram_pair_clear(
        ec_datagram_pair_t *pair /**< Datagram pair. */
        )
{
    unsigned int dev_idx;

    for (dev_idx = EC_DEVICE_MAIN;
            dev_idx < ec_master_num_devices(pair->domain->master);
            dev_idx++) {
        ec_datagram_clear(&pair->datagrams[dev_idx]);
    }

#if EC_MAX_NUM_DEVICES > 1
    if (pair->send_buffer) {
        kfree(pair->send_buffer);
    }
#endif
}
  • 功能和用途:清理 EtherCAT 数据报对。
  • 使用场景:在数据报对不再使用时调用以释放资源。
3. ec_datagram_pair_process
c 复制代码
uint16_t ec_datagram_pair_process(
        ec_datagram_pair_t *pair, /**< Datagram pair. */
        uint16_t wc_sum[] /**< Working counter sums. */
        )
{
    unsigned int dev_idx;
    uint16_t pair_wc = 0;

    for (dev_idx = 0; dev_idx < ec_master_num_devices(pair->domain->master);
            dev_idx++) {
        ec_datagram_t *datagram = &pair->datagrams[dev_idx];

#ifdef EC_RT_SYSLOG
        ec_datagram_output_stats(datagram);
#endif

        if (datagram->state == EC_DATAGRAM_RECEIVED) {
            pair_wc += datagram->working_counter;
            wc_sum[dev_idx] += datagram->working_counter;
        }
    }

    return pair_wc;
}
  • 功能和用途:处理接收到的数据,计算工作计数总和。
  • 使用场景:在需要处理接收到的数据并计算工作计数时调用。

三 h文件翻译

c 复制代码
/******************************************************************************\
 *
 *  $Id$
 *
 *  版权所有 (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
 *
 *  本文件是 IgH EtherCAT 主站的一部分。
 *
 *  IgH EtherCAT 主站是免费软件;您可以根据自由软件基金会发布的 GNU 通用公共许可证第2版的条款重新分发和/或修改它。
 *
 *  IgH EtherCAT 主站的分发目的是希望它有用,但没有任何保证;甚至没有适销性或特定用途适用性的隐含保证。详情请参阅 GNU 通用公共许可证。
 *
 *  您应该已经收到了与 IgH EtherCAT 主站一起提供的 GNU 通用公共许可证的副本;如果没有,请写信给自由软件基金会,地址是:51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA。
 *
 *  ---
 *
 *  上述许可证仅适用于源代码。使用 EtherCAT 技术和品牌仅允许在遵守 Beckhoff Automation GmbH 的工业产权和类似权利的情况下使用。
 *****************************************************************************/

/**
   \file
   EtherCAT 数据报对结构。
*/

/*****************************************************************************/

#ifndef __EC_DATAGRAM_PAIR_H__
#define __EC_DATAGRAM_PAIR_H__

#include <linux/list.h>

#include "globals.h"
#include "datagram.h"

/*****************************************************************************/

/** 域数据报对。
 */
typedef struct {
    struct list_head list; /**< 链表头。 */
    ec_domain_t *domain; /**< 父域。 */
    ec_datagram_t datagrams[EC_MAX_NUM_DEVICES]; /**< 数据报。 */
#if EC_MAX_NUM_DEVICES > 1
    uint8_t *send_buffer;
#endif
    unsigned int expected_working_counter; /**< 期望的工作计数器。 */
} ec_datagram_pair_t;

/*****************************************************************************/

int ec_datagram_pair_init(ec_datagram_pair_t *pair, ec_domain_t *domain,
        uint32_t logical_offset, uint8_t *data, size_t data_size,
        const unsigned int used[]);
void ec_datagram_pair_clear(ec_datagram_pair_t *pair);
uint16_t ec_datagram_pair_process(ec_datagram_pair_t *pair,
        uint16_t wc_sum[]);

/*****************************************************************************/

#endif

四 c文件翻译

c 复制代码
/******************************************************************************\
 *
 *  $Id$
 *
 *  版权所有 (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
 *
 *  本文件是 IgH EtherCAT 主站的一部分。
 *
 *  IgH EtherCAT 主站是免费软件;您可以根据自由软件基金会发布的 GNU 通用公共许可证第2版的条款重新分发和/或修改它。
 *
 *  IgH EtherCAT 主站的分发目的是希望它有用,但没有任何保证;甚至没有适销性或特定用途适用性的隐含保证。详情请参阅 GNU 通用公共许可证。
 *
 *  您应该已经收到了与 IgH EtherCAT 主站一起提供的 GNU 通用公共许可证的副本;如果没有,请写信给自由软件基金会,地址是:51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA。
 *
 *  ---
 *
 *  上述许可证仅适用于源代码。使用 EtherCAT 技术和品牌仅允许在遵守 Beckhoff Automation GmbH 的工业产权和类似权利的情况下使用。
 *****************************************************************************/

/**
   \file
   EtherCAT 数据报对的方法。
*/

/*****************************************************************************/

#include <linux/slab.h>

#include "master.h"
#include "datagram_pair.h"

/*****************************************************************************/

/** 数据报对构造函数。
 *
 * \return 成功时返回零,否则返回负错误代码。
 */
int ec_datagram_pair_init(
        ec_datagram_pair_t *pair, /**< 数据报对。 */
        ec_domain_t *domain, /**< 父域。 */
        uint32_t logical_offset, /**< 逻辑偏移。 */
        uint8_t *data, /**< 数据指针。 */
        size_t data_size, /**< 数据大小。 */
        const unsigned int used[] /**< 输入/输出使用计数。 */
        )
{
    ec_device_index_t dev_idx;
    int ret;

    INIT_LIST_HEAD(&pair->list);
    pair->domain = domain;

    for (dev_idx = EC_DEVICE_MAIN;
            dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
        ec_datagram_init(&pair->datagrams[dev_idx]);
        snprintf(pair->datagrams[dev_idx].name,
                EC_DATAGRAM_NAME_SIZE, "domain%u-%u-%s", domain->index,
                logical_offset, ec_device_names[dev_idx != 0]);
        pair->datagrams[dev_idx].device_index = dev_idx;
    }

    pair->expected_working_counter = 0U;

    for (dev_idx = EC_DEVICE_BACKUP;
            dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
        /* 备份数据报有自己的内存 */
        ret = ec_datagram_prealloc(&pair->datagrams[dev_idx], data_size);
        if (ret) {
            goto out_datagrams;
        }
    }

#if EC_MAX_NUM_DEVICES > 1
    if (!(pair->send_buffer = kmalloc(data_size, GFP_KERNEL))) {
        EC_MASTER_ERR(domain->master,
                "分配域发送缓冲区失败!\n");
        ret = -ENOMEM;
        goto out_datagrams;
    }
#endif

    /* 下面的 ec_datagram_lxx() 调用不会失败,因为数据报有外部内存或已预分配。 */

    if (used[EC_DIR_OUTPUT] && used[EC_DIR_INPUT]) { // 输入和输出
        ec_datagram_lrw_ext(&pair->datagrams[EC_DEVICE_MAIN],
                logical_offset, data_size, data);

        for (dev_idx = EC_DEVICE_BACKUP;
                dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
            ec_datagram_lrw(&pair->datagrams[dev_idx],
                    logical_offset, data_size);
        }

        // 如果使用 LRW,则输出 FMMU 将工作计数器增加 2,
        // 而输入 FMMU 将其增加 1。
        pair->expected_working_counter =
            used[EC_DIR_OUTPUT] * 2 + used[EC_DIR_INPUT];
    } else if (used[EC_DIR_OUTPUT]) { // 仅输出
        ec_datagram_lwr_ext(&pair->datagrams[EC_DEVICE_MAIN],
                logical_offset, data_size, data);
        for (dev_idx = EC_DEVICE_BACKUP;
                dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
            ec_datagram_lwr(&pair->datagrams[dev_idx],
                    logical_offset, data_size);
        }

        pair->expected_working_counter = used[EC_DIR_OUTPUT];
    } else { // 仅输入(或没有)
        ec_datagram_lrd_ext(&pair->datagrams[EC_DEVICE_MAIN],
                logical_offset, data_size, data);
        for (dev_idx = EC_DEVICE_BACKUP;
                dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
            ec_datagram_lrd(&pair->datagrams[dev_idx], logical_offset,
                    data_size);
        }

        pair->expected_working_counter = used[EC_DIR_INPUT];
    }

    for (dev_idx = EC_DEVICE_MAIN;
            dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
        ec_datagram_zero(&pair->datagrams[dev_idx]);
    }

    return 0;

out_datagrams:
    for (dev_idx = EC_DEVICE_MAIN;
            dev_idx < ec_master_num_devices(domain->master); dev_idx++) {
        ec_datagram_clear(&pair->datagrams[dev_idx]);
    }

    return ret;
}

/*****************************************************************************/

/** 数据报对析构函数。
 */
void ec_datagram_pair_clear(
        ec_datagram_pair_t *pair /**< 数据报对。 */
        )
{
    unsigned int dev_idx;

    for (dev_idx = EC_DEVICE_MAIN;
            dev_idx < ec_master_num_devices(pair->domain->master);
            dev_idx++) {
        ec_datagram_clear(&pair->datagrams[dev_idx]);
    }

#if EC_MAX_NUM_DEVICES > 1
    if (pair->send_buffer) {
        kfree(pair->send_buffer);
    }
#endif
}

/*****************************************************************************/

/** 处理接收的数据。
 *
 * \return 所有设备的工作计数器总和。
 */
uint16_t ec_datagram_pair_process(
        ec_datagram_pair_t *pair, /**< 数据报对。 */
        uint16_t wc_sum[] /**< 工作计数器总和。 */
        )
{
    unsigned int dev_idx;
    uint16_t pair_wc = 0;

    for (dev_idx = 0; dev_idx < ec_master_num_devices(pair->domain->master);
            dev_idx++) {
        ec_datagram_t *datagram = &pair->datagrams[dev_idx];

#ifdef EC_RT_SYSLOG
        ec_datagram_output_stats(datagram);
#endif

        if (datagram->state == EC_DATAGRAM_RECEIVED) {
            pair_wc += datagram->working_counter;
            wc_sum[dev_idx] += datagram->working_counter;
        }
    }

    return pair_wc;
}

/*****************************************************************************/

该文档修改记录:

修改时间 修改说明
2024年7月1日 EtherCAT主站IGH 该 文件解析

总结

以上就是EtherCAT主站IGH文件解析的内容。

有不明白的地方欢迎留言;有建议欢迎留言,我后面编写文档好改进。
创作不容,如果文档对您有帮助,记得给个赞。

相关推荐
Uu_05kkq3 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
嵌入式科普5 小时前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
A懿轩A5 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
1 9 J6 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
仍然探索未知中8 小时前
C语言经典100例
c语言
爱吃西瓜的小菜鸡8 小时前
【C语言】矩阵乘法
c语言·学习·算法
Stark、9 小时前
【Linux】文件IO--fcntl/lseek/阻塞与非阻塞/文件偏移
linux·运维·服务器·c语言·后端
deja vu水中芭蕾10 小时前
嵌入式C面试
c语言·开发语言
stm 学习ing11 小时前
HDLBits训练3
c语言·经验分享·笔记·算法·fpga·eda·verilog hdl
CSND74015 小时前
Ubuntu vi(vim)编辑器配置一键补全main函数
linux·c语言·ubuntu·编辑器·vim