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库
- 下载并安装WinPcap运行库:官网:http://www.winpcap.org/install/default.htm

- 运行下载好的exe文件,点击下一步

- 点击同意

- 点击安装

- 点击完成

三. SOEM(1.4)库安装
(1) 编译32位库
-
官网下载SOEM源文件

-
运行VS2019的命令行

-
进入下载好的SOEM源文件

-
在源文件目录下创建build文件夹,并进入
mkdir build cd build
-
运行以下命令,编译源文件
cmake .. -G "NMake Makefiles" nmake
-
运行以下命令生成调用库
namke install
(2) 编译64位库
-
官网下载SOEM源文件

-
运行VS2019的命令行

-
进入下载好的SOEM源文件

-
在源文件目录下创建build文件夹,并进入
mkdir build -
运行以下命令,编译源文件
cmake .. -G "Visual Studio 16 2019" -S . -B build
-
进入build文件夹,用vs2019打开soem.sln项目
namke install
-
点击生成,点击配置管理器

-
选择要生成的内容

-
点击生成解决方案

-
没有报错则完成,可以在debug文件夹中找到生成的库文件


四. 运行SOEM示例代码
-
编译好的SOEM文件夹中有例程(simple_ng)

-
cmd中运行simple_ng,可以看到电脑带的所有的网卡信息

-
选择已经接入EtherCAT从站的网口,复制网口信息(\Device\NPF_{51D73200-BC7C-4562-8918-04FA9C959372}),cmd中运行如下代码
simple_ng \Device\NPF_{51D73200-BC7C-4562-8918-04FA9C959372}
-
通过-map指令,可以查看从站的I/O配置
slaveinfo \Device\NPF_{A837AD34-3738-42FF-8E0B-F5B0BE69ABD6} -map
五. WIN10下利用QT构建SOEM开发环境
-
在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}") -
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(Scalable Open EtherCAT Master 或 Simple Open EtherCAT Master)是一个开源的…...
SpringBoot整合H2数据库并将其打包成jar包、转换成exe文件二(补充)
SpringBoot整合H2数据库并将其打包成jar包、转换成exe文件二(补充) 如果你想在cmd命令窗口内看到程序运行,即点开弹出运行窗口,关闭时exe自动关闭。 需要再launch4j上进行如下操作: 这样转换好的exe就可以有控制台了…...
【kyuubi k8s】kyuubi发布k8s执行spark sql
背景 依据上一篇kyuubi与spark集成,并发布spark sql到k8s集群,上一篇的将kyuubi和spark环境放在本地某台服务器上的,为了高可用,本篇将其打包镜像,并发布到k8s。 其实就是将本地的kyuubi,spark࿰…...
机械装配革新者:3D工艺大师智慧赋能,装配无忧
机械装配,简而言之,就是将各个零件和部件按照严格的技术要求组装起来,使之成为完整且符合标准的机械产品。这一过程不仅要求技术操作的精确性,更强调每个零件之间的完美配合,以确保产品的最终质量和性能达到最优。 常规…...
【C++】const和函数参数
一、const 在 C 中,const 关键字用于定义常量。将 const 关键字放在指针的不同位置,其含义也不同。 1、指向常量的指针 const int* ptr; ptr 是一个指向 const int 的指针,ptr 所指向的值不能通过 ptr 修改,但指针本身可以改变…...
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 #重新分区,转换成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 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,…...
Vue3中VueRouter基本用法及与Vue2中路由使用差异解析
Vue Router 在 Vue3 中被重写,使用了 Vue3 的 Composition API。使用上跟Vue2 相比有些不同,需要注意。 首先,让我们来看一下 Vue3 中 VueRouter 的基本使用方法: 安装 Vue Router: npm install vue-routernext创建…...
10.Docker Compose容器编排
文章目录 Compose简介安装和卸载步骤核心概念compose文件两要素 使用步骤Compose常用命令微服务测试本地编码打包编写Dockerfile文件构建镜像 不使用Compose调试使用Compose调试WordPress测试验证增量更新 Compose简介 docker建议我们每一个容器中只运行一个服务,因为docke…...
【算法——动态规划(从dfs回溯开始推导dp)】
基础理论 递归: 递:大问题分解子问题的过程 ; 归:产生答案 dp:只进行归;用已知的最底层的(递归的边界,搜索树的底),推出未知 《视频索引》 一句话&…...
不是所有洗碗机都能空气除菌 友嘉灵晶空气除菌洗碗机评测
精致的三餐让你以为生活是“享受”,可饭后那些油腻的锅碗瓢盆却成了你我美好生活的最大障碍。想要只吃美食不洗碗,那一台优秀的洗碗机就必不可少了!今天,ZOL中关村在线要评测的就是这样一台不光洗得干净更能有效除菌抑菌的洗碗机—…...
【Linux】如何创建yum 组(yum groups)
如何创建yum 组(yum groups) 在 yum 中创建组信息需要手动编辑并创建一个组文件,然后使用 createrepo 工具生成组信息。以下是一个详细的步骤指南: 1. 创建组信息文件 首先,创建一个 XML 文件来定义组信息。例如,创建一个名为 …...
Linux ssh远程关闭如何保持进程在后台运行的解决方案
问题描述: Unix/Linux下一般想让某个程序在后台运行,很多都是使用 nohup & 在程序结尾让程序自动运行。 使用SSH远程Linux服务器启动应用,都是使用nohup &命令,结果关闭SSH应用仍然挂断了。 我们很多程序并不象mysqld一…...
TypeScript中的泛型
在 TypeScript(简称 TS)中,泛型(Generics)是一种允许你为组件(如类、接口和函数)定义灵活、可重用的类型的方式。泛型可以看作是一种类型参数化,允许你在声明时定义一个或多个类型占…...
LeetCode-2779. 数组的最大美丽值【数组 二分查找 排序 滑动窗口】
LeetCode-2779. 数组的最大美丽值【数组 二分查找 排序 滑动窗口】 题目描述:解题思路一:滑动窗口与排序解题思路二:0解题思路三:0 题目描述: 给你一个下标从 0 开始的整数数组 nums 和一个 非负 整数 k 。 在一步操…...
RIP与OSPF发布默认路由(华为)
#交换设备 RIP与OSPF发布默认路由 合理使用默认路由可以很大程度上减少本地路由表的大小,并可以较好的隐藏一个网络中的路由信息,保护自身网络的隐秘性 另外如果在同一个路由器两端使用了不同的路由协议,那么如果不做路由引入或者发布默认…...
Android 一个改善的okHttp封装库
Android Studio 使用前,对于Android Studio的用户,可以选择添加: compile project(‘:okhttputils’) 或者 compile ‘com.zhy:okhttputils:2.0.0’ Eclipse 自行copy源码。 二、基本用法 目前基本的用法格式为: OkHttpUtils .get()…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果:配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
