一. 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运行库:官网: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 SOEMTest LIBRARY 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]); } 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; }