From 927648a129673ebc51a27a1dd433913f4903b6fa Mon Sep 17 00:00:00 2001 From: lehned Date: Wed, 20 Jul 2022 08:49:05 +0300 Subject: [PATCH 1/2] FoE: corrects ECT_FOE_BUSY handling by resending packet --- soem/ethercatfoe.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/soem/ethercatfoe.c b/soem/ethercatfoe.c index 573cfc0c..ea090f45 100644 --- a/soem/ethercatfoe.c +++ b/soem/ethercatfoe.c @@ -315,7 +315,35 @@ int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 pas } psize += segmentdata; p = (uint8 *)p - segmentdata; - --sendpacket; + sendpacket--; + worktodo = TRUE; + dofinalzero = FALSE; + segmentdata = tsize; + psize -= segmentdata; + /* if last packet was full size, add a zero size packet as final */ + /* EOF is defined as packetsize < full packetsize */ + if (!psize && (segmentdata == maxdata)) + { + dofinalzero = TRUE; + } + FOEp->MbxHeader.length = htoes((uint16)(0x0006 + segmentdata)); + FOEp->MbxHeader.address = htoes(0x0000); + FOEp->MbxHeader.priority = 0x00; + /* get new mailbox count value */ + cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt); + context->slavelist[slave].mbx_cnt = cnt; + FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + MBX_HDR_SET_CNT(cnt); /* FoE */ + FOEp->OpCode = ECT_FOE_DATA; + sendpacket++; + FOEp->PacketNumber = htoel(sendpacket); + memcpy(&FOEp->Data[0], p, segmentdata); + p = (uint8 *)p + segmentdata; + /* send FoE data to slave */ + wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM); + if (wkc <= 0) + { + worktodo = FALSE; + } } break; } From 409847ca261c6477aad146bc51066e2e2f498c22 Mon Sep 17 00:00:00 2001 From: lehned Date: Wed, 20 Jul 2022 08:52:15 +0300 Subject: [PATCH 2/2] adds CMake for win32 examples and enables global win32 for tests --- CMakeLists.txt | 8 +- test/win32/eepromtool/CMakeLists.txt | 5 + test/win32/eoe_test/CMakeLists.txt | 5 + test/win32/eoe_test/eoe_test.c | 420 ++++++++++++++++++++++++++ test/win32/firm_update/CMakeLists.txt | 5 + test/win32/firm_update/firm_update.c | 8 +- test/win32/simple_test/CMakeLists.txt | 5 + test/win32/simple_test/simple_test.c | 2 +- test/win32/slaveinfo/CMakeLists.txt | 5 + 9 files changed, 455 insertions(+), 8 deletions(-) create mode 100644 test/win32/eepromtool/CMakeLists.txt create mode 100644 test/win32/eoe_test/CMakeLists.txt create mode 100644 test/win32/eoe_test/eoe_test.c create mode 100644 test/win32/firm_update/CMakeLists.txt create mode 100644 test/win32/simple_test/CMakeLists.txt create mode 100644 test/win32/slaveinfo/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index baf26bd5..c396a811 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,7 +107,9 @@ install(FILES if(BUILD_TESTS) add_subdirectory(test/simple_ng) - add_subdirectory(test/linux/slaveinfo) - add_subdirectory(test/linux/eepromtool) - add_subdirectory(test/linux/simple_test) + add_subdirectory(test/win32/slaveinfo) + add_subdirectory(test/win32/eepromtool) + add_subdirectory(test/win32/simple_test) + add_subdirectory(test/win32/firm_update) + add_subdirectory(test/win32/eoe_test) endif() diff --git a/test/win32/eepromtool/CMakeLists.txt b/test/win32/eepromtool/CMakeLists.txt new file mode 100644 index 00000000..92d6e1cf --- /dev/null +++ b/test/win32/eepromtool/CMakeLists.txt @@ -0,0 +1,5 @@ + +set(SOURCES eepromtool.c) +add_executable(eepromtool ${SOURCES}) +target_link_libraries(eepromtool soem) +install(TARGETS eepromtool DESTINATION bin) diff --git a/test/win32/eoe_test/CMakeLists.txt b/test/win32/eoe_test/CMakeLists.txt new file mode 100644 index 00000000..c1759e76 --- /dev/null +++ b/test/win32/eoe_test/CMakeLists.txt @@ -0,0 +1,5 @@ + +set(SOURCES eoe_test.c) +add_executable(eoe_test ${SOURCES}) +target_link_libraries(eoe_test soem) +install(TARGETS eoe_test DESTINATION bin) diff --git a/test/win32/eoe_test/eoe_test.c b/test/win32/eoe_test/eoe_test.c new file mode 100644 index 00000000..436e7ddf --- /dev/null +++ b/test/win32/eoe_test/eoe_test.c @@ -0,0 +1,420 @@ +/** \file + * \brief Example code for Simple Open EtherCAT master EoE + * + * This example will run the follwing EoE functions + * SetIP + * GetIP + * + * Loop + * Send fragment data (Layer 2 0x88A4) + * Receive fragment data (Layer 2 0x88A4) + * + * For this to work, a special slave test code is running that + * will bounce the sent 0x88A4 back to receive. + * + * Usage : eoe_test [ifname1] + * ifname is NIC interface, f.e. eth0 + * + * This is a minimal test. + * + * (c)Arthur Ketels 2010 - 2011 + */ + +#include +#include +#include + +#include "ethercat.h" + +#define EC_TIMEOUTMON 500 + +char IOmap[4096]; + +int expectedWKC; +boolean needlf; +volatile int globalwkc; +boolean inOP; +uint8 currentgroup = 0; +OSAL_THREAD_HANDLE thread1; +OSAL_THREAD_HANDLE thread2; +uint8 txbuf[1024]; + +/** Current RX fragment number */ +uint8_t rxfragmentno = 0; +/** Complete RX frame size of current frame */ +uint16_t rxframesize = 0; +/** Current RX data offset in frame */ +uint16_t rxframeoffset = 0; +/** Current RX frame number */ +uint16_t rxframeno = 0; +uint8 rxbuf[1024]; +int size_of_rx = sizeof(rxbuf); + +/** registered EoE hook */ +int eoe_hook(ecx_contextt * context, uint16 slave, void * eoembx) +{ + int wkc; + /* Pass received Mbx data to EoE recevive fragment function that + * that will start/continue fill an Ethernet frame buffer + */ + size_of_rx = sizeof(rxbuf); + wkc = ecx_EOEreadfragment(eoembx, + &rxfragmentno, + &rxframesize, + &rxframeoffset, + &rxframeno, + &size_of_rx, + rxbuf); + + printf("Read frameno %d, fragmentno %d\n", rxframeno, rxfragmentno); + + /* wkc == 1 would mean a frame is complete , last fragment flag have been set and all + * other checks must have past + */ + if (wkc > 0) + { + ec_etherheadert *bp = (ec_etherheadert *)rxbuf; + uint16 type = ntohs(bp->etype); + printf("Frameno %d, type 0x%x complete\n", rxframeno, type); + if (type == ETH_P_ECAT) + { + /* Sanity check that received buffer still is OK */ + if (sizeof(txbuf) != size_of_rx) + { + printf("Size differs, expected %d , received %d\n", (int)sizeof(txbuf), size_of_rx); + } + else + { + printf("Size OK, expected %d , received %d\n", (int)sizeof(txbuf), size_of_rx); + } + /* Check that the TX and RX frames are EQ */ + if (memcmp(rxbuf, txbuf, size_of_rx)) + { + printf("memcmp result != 0\n"); + } + else + { + printf("memcmp result == 0\n"); + } + /* Send a new frame */ + int ixme; + for (ixme = ETH_HEADERSIZE; ixme < sizeof(txbuf); ixme++) + { + txbuf[ixme] = (uint8)rand(); + } + printf("Send a new frame\n"); + ecx_EOEsend(context, 1, 0, sizeof(txbuf), txbuf, EC_TIMEOUTRXM); + } + else + { + printf("Skip type 0x%x\n", type); + } + } + /* No point in returning as unhandled */ + return 1; +} + +OSAL_THREAD_FUNC mailbox_reader(void *lpParam) +{ + ecx_contextt *context = (ecx_contextt *)lpParam; + int wkc; + ec_mbxbuft MbxIn; + ec_mbxheadert * MbxHdr = (ec_mbxheadert *)MbxIn; + + int ixme; + ec_setupheader(&txbuf); + for (ixme = ETH_HEADERSIZE; ixme < sizeof(txbuf); ixme++) + { + txbuf[ixme] = (uint8)rand(); + } + /* Send a made up frame to trigger a fragmented transfer + * Used with a special bound impelmentaion of SOES. Will + * trigger a fragmented transfer back of the same frame. + */ + ecx_EOEsend(context, 1, 0, sizeof(txbuf), txbuf, EC_TIMEOUTRXM); + + for (;;) + { + /* Read mailbox if no other mailbox conversation is ongoing eg. SDOwrite/SDOwrite etc.*/ + wkc = ecx_mbxreceive(context, 1, (ec_mbxbuft *)&MbxIn, 0); + if (wkc > 0) + { + printf("Unhandled mailbox response 0x%x\n", MbxHdr->mbxtype); + } + osal_usleep(1 * 1000 * 1000); + } +} + +void test_eoe(ecx_contextt * context) +{ + /* Set the HOOK */ + ecx_EOEdefinehook(context, eoe_hook); + + eoe_param_t ipsettings, re_ipsettings; + memset(&ipsettings, 0, sizeof(ipsettings)); + memset(&re_ipsettings, 0, sizeof(re_ipsettings)); + + ipsettings.ip_set = 1; + ipsettings.subnet_set = 1; + ipsettings.default_gateway_set = 1; + + EOE_IP4_ADDR_TO_U32(&ipsettings.ip, 192, 168, 9, 200); + EOE_IP4_ADDR_TO_U32(&ipsettings.subnet, 255, 255, 255, 0); + EOE_IP4_ADDR_TO_U32(&ipsettings.default_gateway, 0, 0, 0, 0); + + /* Send a set IP request */ + ecx_EOEsetIp(context, 1, 0, &ipsettings, EC_TIMEOUTRXM); + + /* Send a get IP request, should return the expected IP back */ + ecx_EOEgetIp(context, 1, 0, &re_ipsettings, EC_TIMEOUTRXM); + + /* Trigger an MBX read request, to be replaced by slave Mbx + * full notification via polling of FMMU status process data + */ + printf("recieved IP (%d.%d.%d.%d)\n", + eoe_ip4_addr1(&re_ipsettings.ip), + eoe_ip4_addr2(&re_ipsettings.ip), + eoe_ip4_addr3(&re_ipsettings.ip), + eoe_ip4_addr4(&re_ipsettings.ip)); + printf("recieved subnet (%d.%d.%d.%d)\n", + eoe_ip4_addr1(&re_ipsettings.subnet), + eoe_ip4_addr2(&re_ipsettings.subnet), + eoe_ip4_addr3(&re_ipsettings.subnet), + eoe_ip4_addr4(&re_ipsettings.subnet)); + printf("recieved gateway (%d.%d.%d.%d)\n", + eoe_ip4_addr1(&re_ipsettings.default_gateway), + eoe_ip4_addr2(&re_ipsettings.default_gateway), + eoe_ip4_addr3(&re_ipsettings.default_gateway), + eoe_ip4_addr4(&re_ipsettings.default_gateway)); + + /* Create a asyncronous EoE reader */ + osal_thread_create(&thread2, 128000, &mailbox_reader, &ecx_context); +} + +void teststarter(char *ifname) +{ + int i, oloop, iloop, chk; + needlf = FALSE; + inOP = FALSE; + + printf("Starting eoe test\n"); + + /* initialise SOEM, bind socket to ifname */ + if (ec_init(ifname)) + { + printf("ec_init on %s succeeded.\n",ifname); + /* find and auto-config slaves */ + if ( ec_config_init(FALSE) > 0 ) + { + printf("%d slaves found and configured.\n",ec_slavecount); + + ec_config_map(&IOmap); + + ec_configdc(); + + printf("Slaves mapped, state to SAFE_OP.\n"); + /* wait for all slaves to reach SAFE_OP state */ + ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE * 4); + + oloop = ec_slave[0].Obytes; + if ((oloop == 0) && (ec_slave[0].Obits > 0)) oloop = 1; + if (oloop > 8) oloop = 8; + iloop = ec_slave[0].Ibytes; + if ((iloop == 0) && (ec_slave[0].Ibits > 0)) iloop = 1; + if (iloop > 8) iloop = 8; + + printf("segments : %d : %d %d %d %d\n",ec_group[0].nsegments ,ec_group[0].IOsegment[0],ec_group[0].IOsegment[1],ec_group[0].IOsegment[2],ec_group[0].IOsegment[3]); + + printf("Request operational state for all slaves\n"); + expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC; + printf("Calculated workcounter %d\n", expectedWKC); + ec_slave[0].state = EC_STATE_OPERATIONAL; + /* send one valid process data to make outputs in slaves happy*/ + ec_send_processdata(); + ec_receive_processdata(EC_TIMEOUTRET); + + /* Simple EoE test */ + test_eoe(&ecx_context); + + /* request OP state for all slaves */ + ec_writestate(0); + chk = 200; + /* wait for all slaves to reach OP state */ + do + { + ec_send_processdata(); + ec_receive_processdata(EC_TIMEOUTRET); + ec_statecheck(0, EC_STATE_OPERATIONAL, 50000); + } + while (chk-- && (ec_slave[0].state != EC_STATE_OPERATIONAL)); + if (ec_slave[0].state == EC_STATE_OPERATIONAL ) + { + printf("Operational state reached for all slaves.\n"); + globalwkc = expectedWKC; + inOP = TRUE; + /* cyclic loop */ + for(i = 1; i <= 10000; i++) + { + ec_send_processdata(); + globalwkc = ec_receive_processdata(EC_TIMEOUTRET * 5); +#if PRINT_EOE_INFO_INSTEAD + int j; + if(globalwkc >= expectedWKC) + { + printf("Processdata cycle %4d, WKC %d , O:", i, globalwkc); + for(j = 0 ; j < oloop; j++) + { + printf(" %2.2x", *(ec_slave[0].outputs + j)); + } + printf(" I:"); + for(j = 0 ; j < iloop; j++) + { + printf(" %2.2x", *(ec_slave[0].inputs + j)); + } + printf(" T:%"PRId64"\r",ec_DCtime); + needlf = TRUE; + } +#endif + osal_usleep(1000); + } + inOP = FALSE; + } + else + { + printf("Not all slaves reached operational state.\n"); + ec_readstate(); + for(i = 1; i<=ec_slavecount ; i++) + { + if(ec_slave[i].state != EC_STATE_OPERATIONAL) + { + printf("Slave %d State=0x%2.2x StatusCode=0x%4.4x : %s\n", + i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode)); + } + } + } + printf("\nRequest init state for all slaves\n"); + ec_slave[0].state = EC_STATE_INIT; + /* request INIT state for all slaves */ + ec_writestate(0); + } + else + { + printf("No slaves found!\n"); + } + printf("End eoe test, close socket\n"); + /* stop SOEM, close socket */ + ec_close(); + } + else + { + printf("No socket connection on %s\nExcecute as root\n",ifname); + } +} + +OSAL_THREAD_FUNC ecatcheck( void *ptr ) +{ + int slave; + (void)ptr; /* Not used */ + + while(1) + { + if( inOP && ((globalwkc < expectedWKC) || ec_group[currentgroup].docheckstate)) + { + if (globalwkc < expectedWKC) + { + printf("(wkc < expectedWKC) , globalwkc %d\n", globalwkc); + } + if (ec_group[currentgroup].docheckstate) + { + printf("(ec_group[currentgroup].docheckstate)\n"); + } + + if (needlf) + { + needlf = FALSE; + printf("\n"); + } + /* one ore more slaves are not responding */ + ec_group[currentgroup].docheckstate = FALSE; + ec_readstate(); + for (slave = 1; slave <= ec_slavecount; slave++) + { + if ((ec_slave[slave].group == currentgroup) && (ec_slave[slave].state != EC_STATE_OPERATIONAL)) + { + ec_group[currentgroup].docheckstate = TRUE; + if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR)) + { + printf("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave); + ec_slave[slave].state = (EC_STATE_SAFE_OP + EC_STATE_ACK); + ec_writestate(slave); + } + else if(ec_slave[slave].state == EC_STATE_SAFE_OP) + { + printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave); + ec_slave[slave].state = EC_STATE_OPERATIONAL; + ec_writestate(slave); + } + else if(ec_slave[slave].state > EC_STATE_NONE) + { + if (ec_reconfig_slave(slave, EC_TIMEOUTMON)) + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d reconfigured\n",slave); + } + } + else if(!ec_slave[slave].islost) + { + /* re-check state */ + ec_statecheck(slave, EC_STATE_OPERATIONAL, EC_TIMEOUTRET); + if (ec_slave[slave].state == EC_STATE_NONE) + { + ec_slave[slave].islost = TRUE; + printf("ERROR : slave %d lost\n",slave); + } + } + } + if (ec_slave[slave].islost) + { + if(ec_slave[slave].state == EC_STATE_NONE) + { + if (ec_recover_slave(slave, EC_TIMEOUTMON)) + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d recovered\n",slave); + } + } + else + { + ec_slave[slave].islost = FALSE; + printf("MESSAGE : slave %d found\n",slave); + } + } + } + if(!ec_group[currentgroup].docheckstate) + printf("OK : all slaves resumed OPERATIONAL.\n"); + } + osal_usleep(10000); + } +} + +int main(int argc, char *argv[]) +{ + printf("SOEM (Simple Open EtherCAT Master)\nEoE test\n"); + + if (argc > 1) + { + /* create thread to handle slave error handling in OP */ +// pthread_create( &thread1, NULL, (void *) &ecatcheck, (void*) &ctime); + osal_thread_create(&thread1, 128000, &ecatcheck, (void*) &ctime); + + /* start cyclic part */ + teststarter(argv[1]); + } + else + { + printf("Usage: eoe_test ifname1\nifname = eth0 for example\n"); + } + + printf("End program\n"); + return (0); +} diff --git a/test/win32/firm_update/CMakeLists.txt b/test/win32/firm_update/CMakeLists.txt new file mode 100644 index 00000000..55815cbb --- /dev/null +++ b/test/win32/firm_update/CMakeLists.txt @@ -0,0 +1,5 @@ + +set(SOURCES firm_update.c) +add_executable(firm_update ${SOURCES}) +target_link_libraries(firm_update soem) +install(TARGETS firm_update DESTINATION bin) diff --git a/test/win32/firm_update/firm_update.c b/test/win32/firm_update/firm_update.c index 0cd511e9..c5f4b964 100644 --- a/test/win32/firm_update/firm_update.c +++ b/test/win32/firm_update/firm_update.c @@ -15,12 +15,11 @@ #include #include #include -#include -#include +#include #include "ethercat.h" -#define FWBUFSIZE (8 * 1024 * 1024) +#define FWBUFSIZE (16 * 1024 * 1024) uint8 ob; uint16 ow; @@ -43,6 +42,7 @@ int input_bin(char *fname, int *length) while (((c = fgetc(fp)) != EOF) && (cc < FWBUFSIZE)) filebuffer[cc++] = (uint8)c; *length = cc; + fclose(fp); return 1; } @@ -106,7 +106,7 @@ void boottest(char *ifname, uint16 slave, char *filename) if (ec_statecheck(slave, EC_STATE_BOOT, EC_TIMEOUTSTATE * 10) == EC_STATE_BOOT) { printf("Slave %d state to BOOT.\n", slave); - + filesize = 0; if (input_bin(filename, &filesize)) { printf("File read OK, %d bytes.\n",filesize); diff --git a/test/win32/simple_test/CMakeLists.txt b/test/win32/simple_test/CMakeLists.txt new file mode 100644 index 00000000..196e1996 --- /dev/null +++ b/test/win32/simple_test/CMakeLists.txt @@ -0,0 +1,5 @@ + +set(SOURCES simple_test.c) +add_executable(simple_test ${SOURCES}) +target_link_libraries(simple_test soem) +install(TARGETS simple_test DESTINATION bin) diff --git a/test/win32/simple_test/simple_test.c b/test/win32/simple_test/simple_test.c index d38fbeba..e55b7c73 100644 --- a/test/win32/simple_test/simple_test.c +++ b/test/win32/simple_test/simple_test.c @@ -337,7 +337,7 @@ OSAL_THREAD_FUNC ecatcheck(void *lpParam) osal_usleep(10000); } - return 0; + return; } char ifbuf[1024]; diff --git a/test/win32/slaveinfo/CMakeLists.txt b/test/win32/slaveinfo/CMakeLists.txt new file mode 100644 index 00000000..dd594f2f --- /dev/null +++ b/test/win32/slaveinfo/CMakeLists.txt @@ -0,0 +1,5 @@ + +set(SOURCES slaveinfo.c) +add_executable(slaveinfo ${SOURCES}) +target_link_libraries(slaveinfo soem) +install(TARGETS slaveinfo DESTINATION bin)