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

Windows10 利用QT搭建SOEM开发环境

文章目录

  • 一. 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 SOEMTestLIBRARY 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]);}elseprintf("\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 4printf("Activated SM type workaround, possible incorrect mapping.\n");}if(tSM)tSM += SMt_bug_add; // only add if SMt > 0if (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);elseprintf("  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);elsesi_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;
    }
    

    在这里插入图片描述

相关文章:

Windows10 利用QT搭建SOEM开发环境

文章目录 一. SOEM库简介二. 安装WinPcap三. SOEM(1.4)库安装(1) 编译32位库(2) 编译64位库 四. 运行SOEM示例代码五. WIN10下利用QT构建SOEM开发环境 一. SOEM库简介 SOEM&#xff08;Scalable Open EtherCAT Master 或 Simple Open EtherCAT Master&#xff09;是一个开源的…...

SpringBoot整合H2数据库并将其打包成jar包、转换成exe文件二(补充)

SpringBoot整合H2数据库并将其打包成jar包、转换成exe文件二&#xff08;补充&#xff09; 如果你想在cmd命令窗口内看到程序运行&#xff0c;即点开弹出运行窗口&#xff0c;关闭时exe自动关闭。 需要再launch4j上进行如下操作&#xff1a; 这样转换好的exe就可以有控制台了…...

【kyuubi k8s】kyuubi发布k8s执行spark sql

背景 依据上一篇kyuubi与spark集成&#xff0c;并发布spark sql到k8s集群&#xff0c;上一篇的将kyuubi和spark环境放在本地某台服务器上的&#xff0c;为了高可用&#xff0c;本篇将其打包镜像&#xff0c;并发布到k8s。 其实就是将本地的kyuubi&#xff0c;spark&#xff0…...

机械装配革新者:3D工艺大师智慧赋能,装配无忧

机械装配&#xff0c;简而言之&#xff0c;就是将各个零件和部件按照严格的技术要求组装起来&#xff0c;使之成为完整且符合标准的机械产品。这一过程不仅要求技术操作的精确性&#xff0c;更强调每个零件之间的完美配合&#xff0c;以确保产品的最终质量和性能达到最优。 常规…...

【C++】const和函数参数

一、const 在 C 中&#xff0c;const 关键字用于定义常量。将 const 关键字放在指针的不同位置&#xff0c;其含义也不同。 1、指向常量的指针 const int* ptr; ptr 是一个指向 const int 的指针&#xff0c;ptr 所指向的值不能通过 ptr 修改&#xff0c;但指针本身可以改变…...

2024zjb

单选331/600 下列不属于常用反爬虫手段动是() A访问频度 B验证码校验 C账号权限 D人工筛 题目答案 正确答案:D 330/600 下列不属于聚焦网络爬虫动常用策略动是 A基于深度优先动爬取策略 B基于内容评价动爬取策略 C基于链接结构评价动爬取策略 D基于语境图动爬取策略 题目答案…...

线程池的艺术:深度解析Java多线程并发性能的优化之道

1. 引言 在高并发的Java应用开发中,线程池作为管理和复用线程资源的核心机制,扮演着举足轻重的角色。合理、高效地使用线程池不仅能减少资源消耗、提高系统响应速度,还能有效控制并发线程数量,保证系统的稳定性和性能。 2. 线程池的基本概念与优势 线程池是一种管理和复用…...

Ubuntu server 24 (Linux) 新增磁盘 lvm 动态扩容磁盘空间

1 新增一块硬盘 #查看 sudo fdisk -l #重新分区&#xff0c;转换成lvm类型 sudo fdisk /dev/sdb 2 查看磁盘 df -h3 lvm 配置 #查看lvm逻辑卷 sudo lvdisplay #创建物理卷 sudo pvcreate /dev/sdb1 #扩展卷组 sudo vgextend ubuntu-vg /dev/sdb1 #扩展逻辑卷 sudo lvexte…...

Linux C编译器从零开发三

AST语法树 BNF抽象 expr equality equality relational ("" relational | "!" relational)* relational add ("<" add | "<" add | ">" add | ">" add)* add mul ("" …...

02-ES6新语法

1. ES6 Proxy与Reflect 1.1 概述 Proxy 与 Reflect 是 ES6 为了操作对象引入的 API 。 Proxy 可以对目标对象的读取、函数调用等操作进行拦截&#xff0c;然后进行操作处理。它不直接操作对象&#xff0c;而是像代理模式&#xff0c;通过对象的代理对象进行操作&#xff0c;…...

Vue3中VueRouter基本用法及与Vue2中路由使用差异解析

Vue Router 在 Vue3 中被重写&#xff0c;使用了 Vue3 的 Composition API。使用上跟Vue2 相比有些不同&#xff0c;需要注意。 首先&#xff0c;让我们来看一下 Vue3 中 VueRouter 的基本使用方法&#xff1a; 安装 Vue Router&#xff1a; npm install vue-routernext创建…...

10.Docker Compose容器编排

文章目录 Compose简介安装和卸载步骤核心概念compose文件两要素 使用步骤Compose常用命令微服务测试本地编码打包编写Dockerfile文件构建镜像 不使用Compose调试使用Compose调试WordPress测试验证增量更新 Compose简介 ​ docker建议我们每一个容器中只运行一个服务,因为docke…...

【算法——动态规划(从dfs回溯开始推导dp)】

基础理论 递归&#xff1a; 递&#xff1a;大问题分解子问题的过程 &#xff1b; 归&#xff1a;产生答案 dp&#xff1a;只进行归&#xff1b;用已知的最底层的&#xff08;递归的边界&#xff0c;搜索树的底&#xff09;&#xff0c;推出未知 《视频索引》 一句话&…...

不是所有洗碗机都能空气除菌 友嘉灵晶空气除菌洗碗机评测

精致的三餐让你以为生活是“享受”&#xff0c;可饭后那些油腻的锅碗瓢盆却成了你我美好生活的最大障碍。想要只吃美食不洗碗&#xff0c;那一台优秀的洗碗机就必不可少了&#xff01;今天&#xff0c;ZOL中关村在线要评测的就是这样一台不光洗得干净更能有效除菌抑菌的洗碗机—…...

【Linux】如何创建yum 组(yum groups)

如何创建yum 组(yum groups) 在 yum 中创建组信息需要手动编辑并创建一个组文件&#xff0c;然后使用 createrepo 工具生成组信息。以下是一个详细的步骤指南&#xff1a; 1. 创建组信息文件 首先&#xff0c;创建一个 XML 文件来定义组信息。例如&#xff0c;创建一个名为 …...

Linux ssh远程关闭如何保持进程在后台运行的解决方案

问题描述&#xff1a; Unix/Linux下一般想让某个程序在后台运行&#xff0c;很多都是使用 nohup & 在程序结尾让程序自动运行。 使用SSH远程Linux服务器启动应用&#xff0c;都是使用nohup &命令&#xff0c;结果关闭SSH应用仍然挂断了。 我们很多程序并不象mysqld一…...

TypeScript中的泛型

在 TypeScript&#xff08;简称 TS&#xff09;中&#xff0c;泛型&#xff08;Generics&#xff09;是一种允许你为组件&#xff08;如类、接口和函数&#xff09;定义灵活、可重用的类型的方式。泛型可以看作是一种类型参数化&#xff0c;允许你在声明时定义一个或多个类型占…...

LeetCode-2779. 数组的最大美丽值【数组 二分查找 排序 滑动窗口】

LeetCode-2779. 数组的最大美丽值【数组 二分查找 排序 滑动窗口】 题目描述&#xff1a;解题思路一&#xff1a;滑动窗口与排序解题思路二&#xff1a;0解题思路三&#xff1a;0 题目描述&#xff1a; 给你一个下标从 0 开始的整数数组 nums 和一个 非负 整数 k 。 在一步操…...

RIP与OSPF发布默认路由(华为)

#交换设备 RIP与OSPF发布默认路由 合理使用默认路由可以很大程度上减少本地路由表的大小&#xff0c;并可以较好的隐藏一个网络中的路由信息&#xff0c;保护自身网络的隐秘性 另外如果在同一个路由器两端使用了不同的路由协议&#xff0c;那么如果不做路由引入或者发布默认…...

Android 一个改善的okHttp封装库

Android Studio 使用前&#xff0c;对于Android Studio的用户&#xff0c;可以选择添加: compile project(‘:okhttputils’) 或者 compile ‘com.zhy:okhttputils:2.0.0’ Eclipse 自行copy源码。 二、基本用法 目前基本的用法格式为&#xff1a; OkHttpUtils .get()…...

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 …...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

Kafka主题运维全指南:从基础配置到故障处理

#作者&#xff1a;张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1&#xff1a;主题删除失败。常见错误2&#xff1a;__consumer_offsets占用太多的磁盘。 主题日常管理 …...

若依登录用户名和密码加密

/*** 获取公钥&#xff1a;前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...

云安全与网络安全:核心区别与协同作用解析

在数字化转型的浪潮中&#xff0c;云安全与网络安全作为信息安全的两大支柱&#xff0c;常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异&#xff0c;并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全&#xff1a;聚焦于保…...

图解JavaScript原型:原型链及其分析 | JavaScript图解

​​ 忽略该图的细节&#xff08;如内存地址值没有用二进制&#xff09; 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么&#xff1a;保存在堆中一块区域&#xff0c;同时在栈中有一块区域保存其在堆中的地址&#xff08;也就是我们通常说的该变量指向谁&…...