Windows10 利用QT搭建SOEM开发环境

news2024/11/23 9:44:11

文章目录

  • 一. SOEM库简介
  • 二. 安装WinPcap
  • 三. SOEM(1.4)库安装
    • (1) 编译32位库
    • (2) 编译64位库
  • 四. 运行SOEM示例代码
  • 五. WIN10下利用QT构建SOEM开发环境

一. SOEM库简介

SOEM(Scalable Open EtherCAT Master 或 Simple Open EtherCAT Master)是一个开源的、用于EtherCAT通信协议的软件库。EtherCAT(Ethernet for Control Automation Technology)是一种实时以太网通信协议,广泛应用于自动化和机器人技术中,以其高速和低延迟特性而受到青睐。SOEM库允许开发者在他们的应用程序中实现EtherCAT主站功能,从而控制和驱动EtherCAT从站设备。

以下是SOEM库的一些关键特点和优势:

  • 开源和免费:SOEM是开源的,使用LGPLv2.1授权,可以自由使用、修改和分发。
  • 跨平台支持:SOEM支持多种操作系统,包括Linux、FreeRTOS、VxWorks、QNX等,提供跨平台的灵活性。
  • 实时性能:SOEM直接与硬件交互,确保了低延迟和高数据吞吐量,满足实时性要求。
  • 易于集成:SOEM使用标准的设备驱动模型,简化了在现有系统中添加EtherCAT功能的过程。
  • 文档完善:提供详细的API文档和示例代码,帮助开发者快速上手。
  • 社区支持:作为一个开源项目,SOEM拥有活跃的社区支持,不断有更新和问题解决方案。

SOEM库适用于工业自动化、实验室研究、开源硬件项目和教育用途等多种场景。它为用户应用程序提供了发送和接收EtherCAT帧的方法,支持读写过程数据、保持本地IO数据与全局IO映射同步、检测和管理系统错误等功能。

开发者可以通过研究SOEM的源码来深入理解EtherCAT主站与从站之间的交互方式,这不仅有助于学习EtherCAT协议,还能在此基础上进行定制和优化,以满足特定的应用需求。SOEM项目在GitHub上维护,提供了完整的示例应用和配置文件,方便开发者获取和使用。

二. 安装WinPcap

WinPcap库

  1. 下载并安装WinPcap运行库:官网:http://www.winpcap.org/install/default.htm
    在这里插入图片描述
  2. 运行下载好的exe文件,点击下一步
    在这里插入图片描述
  3. 点击同意
    在这里插入图片描述
  4. 点击安装
    在这里插入图片描述
  5. 点击完成
    在这里插入图片描述

三. SOEM(1.4)库安装

(1) 编译32位库

  1. 官网下载SOEM源文件
    在这里插入图片描述

  2. 运行VS2019的命令行
    在这里插入图片描述

  3. 进入下载好的SOEM源文件
    在这里插入图片描述

  4. 在源文件目录下创建build文件夹,并进入

    mkdir build
    cd build
    

    在这里插入图片描述

  5. 运行以下命令,编译源文件

    cmake .. -G "NMake Makefiles"
    nmake
    

    在这里插入图片描述

  6. 运行以下命令生成调用库

    namke install
    

    在这里插入图片描述

(2) 编译64位库

  1. 官网下载SOEM源文件
    在这里插入图片描述

  2. 运行VS2019的命令行
    在这里插入图片描述

  3. 进入下载好的SOEM源文件
    在这里插入图片描述

  4. 在源文件目录下创建build文件夹,并进入

    mkdir build
    
  5. 运行以下命令,编译源文件

    cmake .. -G "Visual Studio 16 2019" -S . -B build
    

    在这里插入图片描述

  6. 进入build文件夹,用vs2019打开soem.sln项目

    namke install
    

    在这里插入图片描述

  7. 点击生成,点击配置管理器
    在这里插入图片描述

  8. 选择要生成的内容
    在这里插入图片描述

  9. 点击生成解决方案
    在这里插入图片描述

  10. 没有报错则完成,可以在debug文件夹中找到生成的库文件
    在这里插入图片描述
    在这里插入图片描述

四. 运行SOEM示例代码

  1. 编译好的SOEM文件夹中有例程(simple_ng)
    在这里插入图片描述

  2. cmd中运行simple_ng,可以看到电脑带的所有的网卡信息
    在这里插入图片描述

  3. 选择已经接入EtherCAT从站的网口,复制网口信息(\Device\NPF_{51D73200-BC7C-4562-8918-04FA9C959372}),cmd中运行如下代码

    simple_ng \Device\NPF_{51D73200-BC7C-4562-8918-04FA9C959372}
    

    在这里插入图片描述

  4. 通过-map指令,可以查看从站的I/O配置

    slaveinfo \Device\NPF_{A837AD34-3738-42FF-8E0B-F5B0BE69ABD6} -map
    

    在这里插入图片描述

五. WIN10下利用QT构建SOEM开发环境

  1. 在QT中创建一个新c++项目,CMakeList.txt文件如下

    cmake_minimum_required(VERSION 3.5)
    
    project(SOEMTest LANGUAGES CXX)
    
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    set(SOEM_DIR "C:\\Users\\10001540\\Downloads\\SOEM-master")
    include_directories(${SOEM_DIR}\\install\\include\\soem\\ ${SOEM_DIR}\\oshw\\win32\\wpcap\\Include\\)
    link_directories(C:\\Users\\10001540\\Downloads\\SOEM-master\\build\\Debug\\ ${SOEM_DIR}\\oshw\\win32\\wpcap\\Lib\\x64\\)
    
    add_executable(SOEMTest main.cpp)
    
    target_link_libraries(SOEMTest PUBLIC soem.lib Packet.lib wpcap.lib Ws2_32.lib Winmm.lib)
    
    install(TARGETS SOEMTest
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
    
    message(STATUS "The system is: ${CMAKE_SYSTEM_NAME}")
    
  2. main函数中,代码如下:

    #include <iostream>
    #include "ethercat.h"
    
    using namespace std;
    
    char IOmap[4096];
    ec_ODlistt ODlist;
    ec_OElistt OElist;
    boolean printSDO = FALSE;
    boolean printMAP = FALSE;
    char usdo[128];
    char hstr[1024];
    
    char* dtype2string(uint16 dtype)
    {
        switch(dtype)
        {
            case ECT_BOOLEAN:
                sprintf(hstr, "BOOLEAN");
                break;
            case ECT_INTEGER8:
                sprintf(hstr, "INTEGER8");
                break;
            case ECT_INTEGER16:
                sprintf(hstr, "INTEGER16");
                break;
            case ECT_INTEGER32:
                sprintf(hstr, "INTEGER32");
                break;
            case ECT_INTEGER24:
                sprintf(hstr, "INTEGER24");
                break;
            case ECT_INTEGER64:
                sprintf(hstr, "INTEGER64");
                break;
            case ECT_UNSIGNED8:
                sprintf(hstr, "UNSIGNED8");
                break;
            case ECT_UNSIGNED16:
                sprintf(hstr, "UNSIGNED16");
                break;
            case ECT_UNSIGNED32:
                sprintf(hstr, "UNSIGNED32");
                break;
            case ECT_UNSIGNED24:
                sprintf(hstr, "UNSIGNED24");
                break;
            case ECT_UNSIGNED64:
                sprintf(hstr, "UNSIGNED64");
                break;
            case ECT_REAL32:
                sprintf(hstr, "REAL32");
                break;
            case ECT_REAL64:
                sprintf(hstr, "REAL64");
                break;
            case ECT_BIT1:
                sprintf(hstr, "BIT1");
                break;
            case ECT_BIT2:
                sprintf(hstr, "BIT2");
                break;
            case ECT_BIT3:
                sprintf(hstr, "BIT3");
                break;
            case ECT_BIT4:
                sprintf(hstr, "BIT4");
                break;
            case ECT_BIT5:
                sprintf(hstr, "BIT5");
                break;
            case ECT_BIT6:
                sprintf(hstr, "BIT6");
                break;
            case ECT_BIT7:
                sprintf(hstr, "BIT7");
                break;
            case ECT_BIT8:
                sprintf(hstr, "BIT8");
                break;
            case ECT_VISIBLE_STRING:
                sprintf(hstr, "VISIBLE_STRING");
                break;
            case ECT_OCTET_STRING:
                sprintf(hstr, "OCTET_STRING");
                break;
            default:
                sprintf(hstr, "Type 0x%4.4X", dtype);
        }
        return hstr;
    }
    
    char* SDO2string(uint16 slave, uint16 index, uint8 subidx, uint16 dtype)
    {
       int l = sizeof(usdo) - 1, i;
       uint8 *u8;
       int8 *i8;
       uint16 *u16;
       int16 *i16;
       uint32 *u32;
       int32 *i32;
       uint64 *u64;
       int64 *i64;
       float *sr;
       double *dr;
       char es[32];
    
       memset(&usdo, 0, 128);
       ec_SDOread(slave, index, subidx, FALSE, &l, &usdo, EC_TIMEOUTRXM);
       if (EcatError)
       {
          return ec_elist2string();
       }
       else
       {
          switch(dtype)
          {
             case ECT_BOOLEAN:
                u8 = (uint8*) &usdo[0];
                if (*u8) sprintf(hstr, "TRUE");
                 else sprintf(hstr, "FALSE");
                break;
             case ECT_INTEGER8:
                i8 = (int8*) &usdo[0];
                sprintf(hstr, "0x%2.2x %d", *i8, *i8);
                break;
             case ECT_INTEGER16:
                i16 = (int16*) &usdo[0];
                sprintf(hstr, "0x%4.4x %d", *i16, *i16);
                break;
             case ECT_INTEGER32:
             case ECT_INTEGER24:
                i32 = (int32*) &usdo[0];
                sprintf(hstr, "0x%8.8x %d", *i32, *i32);
                break;
             case ECT_INTEGER64:
                i64 = (int64*) &usdo[0];
                //sprintf(hstr, "0x%16.16"PRIx64" %"PRId64, *i64, *i64);
                break;
             case ECT_UNSIGNED8:
                u8 = (uint8*) &usdo[0];
                sprintf(hstr, "0x%2.2x %u", *u8, *u8);
                break;
             case ECT_UNSIGNED16:
                u16 = (uint16*) &usdo[0];
                sprintf(hstr, "0x%4.4x %u", *u16, *u16);
                break;
             case ECT_UNSIGNED32:
             case ECT_UNSIGNED24:
                u32 = (uint32*) &usdo[0];
                sprintf(hstr, "0x%8.8x %u", *u32, *u32);
                break;
             case ECT_UNSIGNED64:
                u64 = (uint64*) &usdo[0];
                //sprintf(hstr, "0x%16.16"PRIx64" %"PRIu64, *u64, *u64);
                break;
             case ECT_REAL32:
                sr = (float*) &usdo[0];
                sprintf(hstr, "%f", *sr);
                break;
             case ECT_REAL64:
                dr = (double*) &usdo[0];
                sprintf(hstr, "%f", *dr);
                break;
             case ECT_BIT1:
             case ECT_BIT2:
             case ECT_BIT3:
             case ECT_BIT4:
             case ECT_BIT5:
             case ECT_BIT6:
             case ECT_BIT7:
             case ECT_BIT8:
                u8 = (uint8*) &usdo[0];
                sprintf(hstr, "0x%x", *u8);
                break;
             case ECT_VISIBLE_STRING:
                strcpy(hstr, usdo);
                break;
             case ECT_OCTET_STRING:
                hstr[0] = 0x00;
                for (i = 0 ; i < l ; i++)
                {
                   sprintf(es, "0x%2.2x ", usdo[i]);
                   strcat( hstr, es);
                }
                break;
             default:
                sprintf(hstr, "Unknown type");
          }
          return hstr;
       }
    }
    
    /** Read PDO assign structure */
    int si_PDOassign(uint16 slave, uint16 PDOassign, int mapoffset, int bitoffset)
    {
        uint16 idxloop, nidx, subidxloop, rdat, idx, subidx;
        uint8 subcnt;
        int wkc, bsize = 0, rdl;
        int32 rdat2;
        uint8 bitlen, obj_subidx;
        uint16 obj_idx;
        int abs_offset, abs_bit;
    
        rdl = sizeof(rdat); rdat = 0;
        /* read PDO assign subindex 0 ( = number of PDO's) */
        wkc = ec_SDOread(slave, PDOassign, 0x00, FALSE, &rdl, &rdat, EC_TIMEOUTRXM);
        rdat = etohs(rdat);
        /* positive result from slave ? */
        if ((wkc > 0) && (rdat > 0))
        {
            /* number of available sub indexes */
            nidx = rdat;
            bsize = 0;
            /* read all PDO's */
            for (idxloop = 1; idxloop <= nidx; idxloop++)
            {
                rdl = sizeof(rdat); rdat = 0;
                /* read PDO assign */
                wkc = ec_SDOread(slave, PDOassign, (uint8)idxloop, FALSE, &rdl, &rdat, EC_TIMEOUTRXM);
                /* result is index of PDO */
                idx = etohl(rdat);
                if (idx > 0)
                {
                    rdl = sizeof(subcnt); subcnt = 0;
                    /* read number of subindexes of PDO */
                    wkc = ec_SDOread(slave,idx, 0x00, FALSE, &rdl, &subcnt, EC_TIMEOUTRXM);
                    subidx = subcnt;
                    /* for each subindex */
                    for (subidxloop = 1; subidxloop <= subidx; subidxloop++)
                    {
                        rdl = sizeof(rdat2); rdat2 = 0;
                        /* read SDO that is mapped in PDO */
                        wkc = ec_SDOread(slave, idx, (uint8)subidxloop, FALSE, &rdl, &rdat2, EC_TIMEOUTRXM);
                        rdat2 = etohl(rdat2);
                        /* extract bitlength of SDO */
                        bitlen = LO_BYTE(rdat2);
                        bsize += bitlen;
                        obj_idx = (uint16)(rdat2 >> 16);
                        obj_subidx = (uint8)((rdat2 >> 8) & 0x000000ff);
                        abs_offset = mapoffset + (bitoffset / 8);
                        abs_bit = bitoffset % 8;
                        ODlist.Slave = slave;
                        ODlist.Index[0] = obj_idx;
                        OElist.Entries = 0;
                        wkc = 0;
                        /* read object entry from dictionary if not a filler (0x0000:0x00) */
                        if(obj_idx || obj_subidx)
                            wkc = ec_readOEsingle(0, obj_subidx, &ODlist, &OElist);
                        printf("  [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen);
                        if((wkc > 0) && OElist.Entries)
                        {
                            printf(" %-12s %s\n", dtype2string(OElist.DataType[obj_subidx]), OElist.Name[obj_subidx]);
                        }
                        else
                            printf("\n");
                        bitoffset += bitlen;
                    };
                };
            };
        };
        /* return total found bitlength (PDO) */
        return bsize;
    }
    
    int si_map_sdo(int slave)
    {
        int wkc, rdl;
        int retVal = 0;
        uint8 nSM, iSM, tSM;
        int Tsize, outputs_bo, inputs_bo;
        uint8 SMt_bug_add;
    
        printf("PDO mapping according to CoE :\n");
        SMt_bug_add = 0;
        outputs_bo = 0;
        inputs_bo = 0;
        rdl = sizeof(nSM); nSM = 0;
        /* read SyncManager Communication Type object count */
        wkc = ec_SDOread(slave, ECT_SDO_SMCOMMTYPE, 0x00, FALSE, &rdl, &nSM, EC_TIMEOUTRXM);
        /* positive result from slave ? */
        if ((wkc > 0) && (nSM > 2))
        {
            /* make nSM equal to number of defined SM */
            nSM--;
            /* limit to maximum number of SM defined, if true the slave can't be configured */
            if (nSM > EC_MAXSM)
                nSM = EC_MAXSM;
            /* iterate for every SM type defined */
            for (iSM = 2 ; iSM <= nSM ; iSM++)
            {
                rdl = sizeof(tSM); tSM = 0;
                /* read SyncManager Communication Type */
                wkc = ec_SDOread(slave, ECT_SDO_SMCOMMTYPE, iSM + 1, FALSE, &rdl, &tSM, EC_TIMEOUTRXM);
                if (wkc > 0)
                {
                    if((iSM == 2) && (tSM == 2)) // SM2 has type 2 == mailbox out, this is a bug in the slave!
                    {
                        SMt_bug_add = 1; // try to correct, this works if the types are 0 1 2 3 and should be 1 2 3 4
                        printf("Activated SM type workaround, possible incorrect mapping.\n");
                    }
                    if(tSM)
                        tSM += SMt_bug_add; // only add if SMt > 0
    
                    if (tSM == 3) // outputs
                    {
                        /* read the assign RXPDO */
                        printf("  SM%1d outputs\n     addr b   index: sub bitl data_type    name\n", iSM);
                        Tsize = si_PDOassign(slave, ECT_SDO_PDOASSIGN + iSM, (int)(ec_slave[slave].outputs - (uint8 *)&IOmap[0]), outputs_bo );
                        outputs_bo += Tsize;
                    }
                    if (tSM == 4) // inputs
                    {
                        /* read the assign TXPDO */
                        printf("  SM%1d inputs\n     addr b   index: sub bitl data_type    name\n", iSM);
                        Tsize = si_PDOassign(slave, ECT_SDO_PDOASSIGN + iSM, (int)(ec_slave[slave].inputs - (uint8 *)&IOmap[0]), inputs_bo );
                        inputs_bo += Tsize;
                    }
                }
            }
        }
    
        /* found some I/O bits ? */
        if ((outputs_bo > 0) || (inputs_bo > 0))
            retVal = 1;
        return retVal;
    }
    
    int si_siiPDO(uint16 slave, uint8 t, int mapoffset, int bitoffset)
    {
        uint16 a , w, c, e, er, Size;
        uint8 eectl;
        uint16 obj_idx;
        uint8 obj_subidx;
        uint8 obj_name;
        uint8 obj_datatype;
        uint8 bitlen;
        int totalsize;
        ec_eepromPDOt eepPDO;
        ec_eepromPDOt *PDO;
        int abs_offset, abs_bit;
        char str_name[EC_MAXNAME + 1];
    
        eectl = ec_slave[slave].eep_pdi;
        Size = 0;
        totalsize = 0;
        PDO = &eepPDO;
        PDO->nPDO = 0;
        PDO->Length = 0;
        PDO->Index[1] = 0;
        for (c = 0 ; c < EC_MAXSM ; c++) PDO->SMbitsize[c] = 0;
        if (t > 1)
            t = 1;
        PDO->Startpos = ec_siifind(slave, ECT_SII_PDO + t);
        if (PDO->Startpos > 0)
        {
            a = PDO->Startpos;
            w = ec_siigetbyte(slave, a++);
            w += (ec_siigetbyte(slave, a++) << 8);
            PDO->Length = w;
            c = 1;
            /* traverse through all PDOs */
            do
            {
                PDO->nPDO++;
                PDO->Index[PDO->nPDO] = ec_siigetbyte(slave, a++);
                PDO->Index[PDO->nPDO] += (ec_siigetbyte(slave, a++) << 8);
                PDO->BitSize[PDO->nPDO] = 0;
                c++;
                /* number of entries in PDO */
                e = ec_siigetbyte(slave, a++);
                PDO->SyncM[PDO->nPDO] = ec_siigetbyte(slave, a++);
                a++;
                obj_name = ec_siigetbyte(slave, a++);
                a += 2;
                c += 2;
                if (PDO->SyncM[PDO->nPDO] < EC_MAXSM) /* active and in range SM? */
                {
                    str_name[0] = 0;
                    if(obj_name)
                      ec_siistring(str_name, slave, obj_name);
                    if (t)
                      printf("  SM%1d RXPDO 0x%4.4X %s\n", PDO->SyncM[PDO->nPDO], PDO->Index[PDO->nPDO], str_name);
                    else
                      printf("  SM%1d TXPDO 0x%4.4X %s\n", PDO->SyncM[PDO->nPDO], PDO->Index[PDO->nPDO], str_name);
                    printf("     addr b   index: sub bitl data_type    name\n");
                    /* read all entries defined in PDO */
                    for (er = 1; er <= e; er++)
                    {
                        c += 4;
                        obj_idx = ec_siigetbyte(slave, a++);
                        obj_idx += (ec_siigetbyte(slave, a++) << 8);
                        obj_subidx = ec_siigetbyte(slave, a++);
                        obj_name = ec_siigetbyte(slave, a++);
                        obj_datatype = ec_siigetbyte(slave, a++);
                        bitlen = ec_siigetbyte(slave, a++);
                        abs_offset = mapoffset + (bitoffset / 8);
                        abs_bit = bitoffset % 8;
    
                        PDO->BitSize[PDO->nPDO] += bitlen;
                        a += 2;
    
                        str_name[0] = 0;
                        if(obj_name)
                          ec_siistring(str_name, slave, obj_name);
    
                        printf("  [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen);
                        printf(" %-12s %s\n", dtype2string(obj_datatype), str_name);
                        bitoffset += bitlen;
                        totalsize += bitlen;
                    }
                    PDO->SMbitsize[ PDO->SyncM[PDO->nPDO] ] += PDO->BitSize[PDO->nPDO];
                    Size += PDO->BitSize[PDO->nPDO];
                    c++;
                }
                else /* PDO deactivated because SM is 0xff or > EC_MAXSM */
                {
                    c += 4 * e;
                    a += 8 * e;
                    c++;
                }
                if (PDO->nPDO >= (EC_MAXEEPDO - 1)) c = PDO->Length; /* limit number of PDO entries in buffer */
            }
            while (c < PDO->Length);
        }
        if (eectl) ec_eeprom2pdi(slave); /* if eeprom control was previously pdi then restore */
        return totalsize;
    }
    
    int si_map_sii(int slave)
    {
        int retVal = 0;
        int Tsize, outputs_bo, inputs_bo;
    
        printf("PDO mapping according to SII :\n");
    
        outputs_bo = 0;
        inputs_bo = 0;
        /* read the assign RXPDOs */
        Tsize = si_siiPDO(slave, 1, (int)(ec_slave[slave].outputs - (uint8*)&IOmap), outputs_bo );
        outputs_bo += Tsize;
        /* read the assign TXPDOs */
        Tsize = si_siiPDO(slave, 0, (int)(ec_slave[slave].inputs - (uint8*)&IOmap), inputs_bo );
        inputs_bo += Tsize;
        /* found some I/O bits ? */
        if ((outputs_bo > 0) || (inputs_bo > 0))
            retVal = 1;
        return retVal;
    }
    
    void si_sdo(int cnt)
    {
        int i, j;
    
        ODlist.Entries = 0;
        memset(&ODlist, 0, sizeof(ODlist));
        if( ec_readODlist(cnt, &ODlist))
        {
            printf(" CoE Object Description found, %d entries.\n",ODlist.Entries);
            for( i = 0 ; i < ODlist.Entries ; i++)
            {
                ec_readODdescription(i, &ODlist);
                while(EcatError) printf("%s", ec_elist2string());
                printf(" Index: %4.4x Datatype: %4.4x Objectcode: %2.2x Name: %s\n",
                    ODlist.Index[i], ODlist.DataType[i], ODlist.ObjectCode[i], ODlist.Name[i]);
                memset(&OElist, 0, sizeof(OElist));
                ec_readOE(i, &ODlist, &OElist);
                while(EcatError) printf("%s", ec_elist2string());
                for( j = 0 ; j < ODlist.MaxSub[i]+1 ; j++)
                {
                    if ((OElist.DataType[j] > 0) && (OElist.BitLength[j] > 0))
                    {
                        printf("  Sub: %2.2x Datatype: %4.4x Bitlength: %4.4x Obj.access: %4.4x Name: %s\n",
                            j, OElist.DataType[j], OElist.BitLength[j], OElist.ObjAccess[j], OElist.Name[j]);
                        if ((OElist.ObjAccess[j] & 0x0007))
                        {
                            printf("          Value :%s\n", SDO2string(cnt, ODlist.Index[i], j, OElist.DataType[j]));
                        }
                    }
                }
            }
        }
        else
        {
            while(EcatError) printf("%s", ec_elist2string());
        }
    }
    
    void slaveinfo(char *ifname)
    {
        int cnt, i, j, nSM;
        uint16 ssigen;
        int expectedWKC;
        ecx_contextt* contex;
    
        printf("Starting slaveinfo\n");
    
        if(ec_init(ifname)) // 初始化SOEM库,绑定soket到网口
        {
            printf("ec_init on %s succeeded.\n",ifname);
            if(ec_config(FALSE, &IOmap) > 0) // 枚举所有从站的信息,并配置从站,保存到IOmap中
            {
                ec_configdc();
                while(EcatError)
                {
                    cout<< ec_elist2string() << endl;
                }
                printf("%d slaves found and configured.\n",ec_slavecount);
                expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC;
                printf("Calculated workcounter %d\n", expectedWKC);
                ec_statecheck(0, EC_STATE_SAFE_OP,  EC_TIMEOUTSTATE * 3);
                if (ec_slave[0].state != EC_STATE_SAFE_OP )
                {
                    printf("Not all slaves reached safe operational state.\n");
                    ec_readstate();
                    for(i = 1; i<=ec_slavecount ; i++)
                    {
                       if(ec_slave[i].state != EC_STATE_SAFE_OP)
                       {
                           printf("Slave %d State=%2x StatusCode=%4x : %s\n",
                                                i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode));
                       }
                    }
                }
    
                ec_readstate();
                for( cnt = 1 ; cnt <= ec_slavecount ; cnt++)
                {
                   printf("\nSlave:%d\n Name:%s\n Output size: %dbits\n Input size: %dbits\n State: %d\n Delay: %d[ns]\n Has DC: %d\n",
                         cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits,
                         ec_slave[cnt].state, ec_slave[cnt].pdelay, ec_slave[cnt].hasdc);
                   if (ec_slave[cnt].hasdc) printf(" DCParentport:%d\n", ec_slave[cnt].parentport);
                   printf(" Activeports:%d.%d.%d.%d\n", (ec_slave[cnt].activeports & 0x01) > 0 ,
                                                (ec_slave[cnt].activeports & 0x02) > 0 ,
                                                (ec_slave[cnt].activeports & 0x04) > 0 ,
                                                (ec_slave[cnt].activeports & 0x08) > 0 );
                   printf(" Configured address: %4.4x\n", ec_slave[cnt].configadr);
                   printf(" Man: %8.8x ID: %8.8x Rev: %8.8x\n", (int)ec_slave[cnt].eep_man, (int)ec_slave[cnt].eep_id, (int)ec_slave[cnt].eep_rev);
                   for(nSM = 0 ; nSM < EC_MAXSM ; nSM++)
                   {
                      if(ec_slave[cnt].SM[nSM].StartAddr > 0)
                         printf(" SM%1d A:%4.4x L:%4d F:%8.8x Type:%d\n",nSM, ec_slave[cnt].SM[nSM].StartAddr, ec_slave[cnt].SM[nSM].SMlength,
                                (int)ec_slave[cnt].SM[nSM].SMflags, ec_slave[cnt].SMtype[nSM]);
                   }
                   for(j = 0 ; j < ec_slave[cnt].FMMUunused ; j++)
                   {
                      printf(" FMMU%1d Ls:%8.8x Ll:%4d Lsb:%d Leb:%d Ps:%4.4x Psb:%d Ty:%2.2x Act:%2.2x\n", j,
                              (int)ec_slave[cnt].FMMU[j].LogStart, ec_slave[cnt].FMMU[j].LogLength, ec_slave[cnt].FMMU[j].LogStartbit,
                              ec_slave[cnt].FMMU[j].LogEndbit, ec_slave[cnt].FMMU[j].PhysStart, ec_slave[cnt].FMMU[j].PhysStartBit,
                              ec_slave[cnt].FMMU[j].FMMUtype, ec_slave[cnt].FMMU[j].FMMUactive);
                   }
                   printf(" FMMUfunc 0:%d 1:%d 2:%d 3:%d\n",
                            ec_slave[cnt].FMMU0func, ec_slave[cnt].FMMU1func, ec_slave[cnt].FMMU2func, ec_slave[cnt].FMMU3func);
                   printf(" MBX length wr: %d rd: %d MBX protocols : %2.2x\n", ec_slave[cnt].mbx_l, ec_slave[cnt].mbx_rl, ec_slave[cnt].mbx_proto);
                   ssigen = ec_siifind(cnt, ECT_SII_GENERAL);
                   /* SII general section */
                   if (ssigen)
                   {
                      ec_slave[cnt].CoEdetails = ec_siigetbyte(cnt, ssigen + 0x07);
                      ec_slave[cnt].FoEdetails = ec_siigetbyte(cnt, ssigen + 0x08);
                      ec_slave[cnt].EoEdetails = ec_siigetbyte(cnt, ssigen + 0x09);
                      ec_slave[cnt].SoEdetails = ec_siigetbyte(cnt, ssigen + 0x0a);
                      if((ec_siigetbyte(cnt, ssigen + 0x0d) & 0x02) > 0)
                      {
                         ec_slave[cnt].blockLRW = 1;
                         ec_slave[0].blockLRW++;
                      }
                      ec_slave[cnt].Ebuscurrent = ec_siigetbyte(cnt, ssigen + 0x0e);
                      ec_slave[cnt].Ebuscurrent += ec_siigetbyte(cnt, ssigen + 0x0f) << 8;
                      ec_slave[0].Ebuscurrent += ec_slave[cnt].Ebuscurrent;
                   }
                   printf(" CoE details: %2.2x FoE details: %2.2x EoE details: %2.2x SoE details: %2.2x\n",
                           ec_slave[cnt].CoEdetails, ec_slave[cnt].FoEdetails, ec_slave[cnt].EoEdetails, ec_slave[cnt].SoEdetails);
                   printf(" Ebus current: %d[mA]\n only LRD/LWR:%d\n",
                           ec_slave[cnt].Ebuscurrent, ec_slave[cnt].blockLRW);
                   if ((ec_slave[cnt].mbx_proto & ECT_MBXPROT_COE) && printSDO)
                   {
                           si_sdo(cnt);
                   }
    
                   if (ec_slave[cnt].mbx_proto & ECT_MBXPROT_COE)
                       si_map_sdo(cnt);
                   else
                       si_map_sii(cnt);
    
                }
    
            }
        }
        else
        {
        }
    }
    
    int main()
    {
        char* ifbuf = "\\Device\\NPF_{A837AD34-3738-42FF-8E0B-F5B0BE69ABD6}"; // 网口设备号
        printf("SOEM (Simple Open EtherCAT Master)\nSlaveinfo\n");
        slaveinfo(ifbuf);
        return 0;
    }
    

    在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SwiftUI 6.0(iOS 18)新容器视图修改器漫谈

概览 本届 WWDC 2024 观影正如火如荼的进行中&#xff0c;一片鸟语花香、枝繁叶茂的苹果树上不时结出几颗令人垂涎欲滴的美味苹果让秃头码农们欲罢不能。 如您所愿&#xff0c;在界面布局“利器” SwiftUI 这根蔓藤也长出不少喜人的果实&#xff0c;其中在 iOS 18.0 中新添加的…

1949年到2021年中国历年稻谷产量统计报告

数据介绍 数据来源于国家统计局&#xff0c;为1949年到2021年我国每年的稻谷产量数据。 2021年&#xff0c;我国稻谷产量为21284.24万吨&#xff0c;比上年增长0.5%。 数据统计单位为&#xff1a;万吨 我国稻谷产量有多少&#xff1f; 2021年&#xff0c;我国稻谷产量为2128…

TIA Portal 博途西门子自动化编程软件下载安装,TIA Portal 提高生产效率!

驱动编程功能则是TIA Portal的又一亮点&#xff0c;它支持各种驱动器的编程和配置&#xff0c;使设备能够精准地执行各种运动控制任务。此外&#xff0c;SCADA&#xff08;监控与数据采集&#xff09;编程功能使得用户可以实时监控生产过程的各项数据&#xff0c;确保生产过程的…

全网爆火的AI语音合成工具-ChatTTS,有人已经拿它赚到了第一桶金,送增强版整合包

上篇分享了如何从0到1搭建一套语音交互系统。 其中&#xff0c;语音合成&#xff08;TTS&#xff09;是提升用户体验的关键所在。 不得不说&#xff0c;AI 语音界人才辈出&#xff0c;从之前的Bert-Sovit&#xff0c;到GPT-Sovits&#xff0c;再到最近一周狂揽了 1w Star 的C…

在顺序表中使用顺序查找法查找某个关键字

//顺序表中顺序查找(SeqSearch) #include<stdio.h> #include<stdlib.h> #define MAX 100 #include<assert.h> typedef struct {int data[MAX];int length; }SeqList; int SeqSearch(SeqList* S, int key)//key为要查找的值 {printf("关键字序列&#xf…

11.泛型、trait和生命周期(上)

标题 一、泛型数据的引入二、改写为泛型函数三、结构体/枚举中的泛型定义四、方法定义中的泛型 一、泛型数据的引入 下面是两个函数&#xff0c;分别用来取得整型和符号型vector中的最大值 use std::fs::File;fn get_max_float_value_from_vector(src: &[f64]) -> f64…

转让注册地址在北京的无区域投资管理集团公司

公司名称中不带省市地域&#xff0c;或是公司名称没有行业表述的公司&#xff0c;都是要在工商总局进行核名的&#xff0c;我们简称为总局无区域核名公司&#xff0c;此类公司的注册须经总局局批准&#xff0c;名称可以不带省市地域、行业特点&#xff0c;现在公司名称新核准已…

LeetCode206-反转链表

题目 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 代码 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* …

【网络编程】进程间的通信

进程间通信意味着两个不同进程间交换数据&#xff0c;操作系统中应提供两个进程可以同时访问内存空间。 管道实现进程间通信 管道不属于进程资源&#xff0c;与套接字一样属于操作系统。两个进程通过操作系统提供内存空间进行通信 #include<unistd.h> int pipe(int fil…

高考志愿填报,如何选择大学专业?

选择大学专业是一件需要谨慎的事情&#xff0c;需要综合考虑各个因素。大学专业和将来的就业方向是一致的&#xff0c;选专业实际就是在选职业&#xff0c;选自己未来几十年的职业生活。如何去选择大学专业&#xff0c;建议从个人兴趣&#xff0c;个人优势能力&#xff0c;职业…

大家来决定:python-office运行时的提示信息,要不要删除?

​ 大家好&#xff0c;这里是程序员晚枫&#xff0c;今天想请大家投票决定一下&#xff1a;运行python-office时的下面这种中文提示信息&#xff0c;要不要全部都取消了&#xff1f;&#x1f447; 为什么加这个提示&#xff1f; 我是在2022年发布的这个开源项目&#xff0c;并…

Ctrl+Back(回退键)快捷键失效,导致IDEA不能删除多个字符

CtrlBackspace快捷键差不多失效了2年&#xff0c;因为没怎么用笔记本了&#xff0c;所以就没管。这阵子开始用了&#xff0c;在Idea里面不能通过CtrlBack的方式删除&#xff0c;只能一个个字符删除&#xff0c;真的难受。 后面尝试退出一些软件&#xff0c;停止一些服务&#x…

Bio-Info每日一题:Rosalind-07-Mendel‘s First Law(孟德尔第一定律 python实现)

&#x1f389; 进入生物信息学的世界&#xff0c;与Rosalind一起探索吧&#xff01;&#x1f9ec; Rosalind是一个在线平台&#xff0c;专为学习和实践生物信息学而设计。该平台提供了一系列循序渐进的编程挑战&#xff0c;帮助用户从基础到高级掌握生物信息学知识。无论你是初…

5000天后的世界

为何可以预见未来 1993年&#xff0c;在互联网的黎明时代&#xff0c;凯文凯利创办了《连线》杂志。他曾经采访过以比尔盖茨、史蒂夫乔布斯、杰夫贝佐斯为代表的一众风云创业家。《连线》杂志是全球发行的世界著名杂志&#xff0c;一直致力于报道科学技术带来的经济、社会变革…

特种设备观光车司机N2精选模拟试题

11、过电压继电器的返回电压与动作电压之比称为过电压继电器的返回系数。(√) 12、部门规章和地方政府规章都属于行政规章。(√) 13、在没有障碍时&#xff0c;倒车的车速应快一些&#xff0c;以免防碍交通。()(x) 14、场(厂)内专用机动车辆的安全运行&#xff0c;由使用单位…

LabVIEW开发中的常见通讯协议详解

介绍LabVIEW开发中常见的通讯协议&#xff0c;包括RS-232、RS-485、I2C、SPI、CAN、Ethernet、Modbus和GPIB等。通过对各协议的具体内容、特点、使用范围及注意事项进行全面解析&#xff0c;帮助开发者选择合适的通讯协议&#xff0c;提高系统性能和可靠性。 1. RS-232 内容&a…

打造成功的人力RPO项目:赢得市场赚取利润

人力资源外包(RPO)项目是当今企业在招聘和人才管理方面越来越倾向的选择。想要通过人力RPO项目赚钱&#xff0c;以下是一些关键的策略和步骤&#xff0c;帮助您进入这个市场并取得成功。 1. 建立专业的人力RPO服务 首先&#xff0c;要想在人力RPO项目中赚钱&#xff0c;必须建立…

【私有云】cdn无法回源到私有云怎么办?快速落地

私有云如何使用cdn加速 文章后&#xff0c;产生的后续问题解决&#xff1a; 背景&#xff1a; 由于公司上新系统&#xff0c;使用人数数量大&#xff0c;在查看课件资源时&#xff0c;出现卡段现象&#xff0c;减少公司带宽占用&#xff0c;故使用cdn加速。但领导又要求资源…

【云原生】Kubernetes----Kubernetes集群部署Prometheus 和Grafana

目录 引言 一、环境准备 二、部署node-exporter &#xff08;一&#xff09;创建命名空间 &#xff08;二&#xff09;部署node-exporter 1.获取镜像 2.定义yaml文件 3.创建服务 4.查看监控数据 三、部署Prometheus &#xff08;一&#xff09;创建账号并授权 &…

赶紧转行大模型,预计风口就今年一年,明年市场就饱和了!不是开玩笑

恕我直言&#xff0c;就这几天&#xff0c;各大厂都在裁员&#xff0c;什么开发测试运维都裁&#xff0c;只有大模型是急招人。 你说你不知道大模型是什么&#xff1f;那可太对了&#xff0c;你不知道说明别人也不知道&#xff0c;就是要趁只有业内部分人知道的时候入局&#…