Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support larger mailbox sizes for FoE #623

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,10 @@ install(FILES
${OSHW_HEADERS}
DESTINATION ${SOEM_INCLUDE_INSTALL_DIR})

if(BUILD_TESTS)
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/linux/firm_update)
endif()
9 changes: 8 additions & 1 deletion soem/ethercatbase.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,14 @@ int ecx_FPRD(ecx_portt *port, uint16 ADP, uint16 ADO, uint16 length, void *data,
wkc = ecx_srconfirm(port, idx, timeout);
if (wkc > 0)
{
memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);
if (length <= EC_MAXMBX)
{
memcpy(data, &(port->rxbuf[idx][EC_HEADERSIZE]), length);
}
else
{
wkc = EC_ERROR;
}
}
ecx_setbufstat(port, idx, EC_BUF_EMPTY);

Expand Down
42 changes: 37 additions & 5 deletions soem/ethercatfoe.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include "ethercatmain.h"
#include "ethercatfoe.h"

#define EC_MAXFOEDATA 512
#define EC_MAXFOEDATA EC_MAXMBX

/** FOE structure.
* Used for Read, Write, Data, Ack and Error mailbox packets.
Expand Down Expand Up @@ -309,13 +309,45 @@ int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 pas
/* otherwise ignore */
if (sendpacket)
{
if (!psize)
{
dofinalzero = TRUE;
}
psize += segmentdata;
p = (uint8 *)p - segmentdata;
--sendpacket;
tsize = psize;
if (tsize > maxdata)
{
tsize = maxdata;
}
if(tsize || dofinalzero)
{
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(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 + (cnt << 4); /* 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;
}
Expand Down
5 changes: 5 additions & 0 deletions test/linux/firm_update/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
145 changes: 119 additions & 26 deletions test/linux/firm_update/firm_update.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,26 @@

#include "ethercat.h"

#define FWBUFSIZE (8 * 1024 * 1024)
#define FWBUFSIZE (20 * 1024 * 1024)

uint8 ob;
uint16 ow;
uint32 data;
char filename[256];
char filebuffer[FWBUFSIZE]; // 8MB buffer
char filebuffer[FWBUFSIZE]; // 20MB buffer
int filesize;
int j;
uint16 argslave;

int input_bin(char *fname, int *length)
{
FILE *fp;
FILE *fp;

int cc = 0, c;

fp = fopen(fname, "rb");
if(fp == NULL)
return 0;
fp = fopen(fname, "rb");
if(fp == NULL)
return 0;
while (((c = fgetc(fp)) != EOF) && (cc < FWBUFSIZE))
filebuffer[cc++] = (uint8)c;
*length = cc;
Expand All @@ -48,8 +48,9 @@ int input_bin(char *fname, int *length)
}


void boottest(char *ifname, uint16 slave, char *filename)
int boottest(char *ifname, uint16 slave, char *filename)
{
int retval = 0;
printf("Starting firmware update example\n");

/* initialise SOEM, bind socket to ifname */
Expand All @@ -61,18 +62,48 @@ void boottest(char *ifname, uint16 slave, char *filename)

if ( ec_config_init(FALSE) > 0 )
{
int counter = 3;
char sm_zero[sizeof(ec_smt)*2];
char fmmu_zero[sizeof(ec_fmmut)];
unsigned char rd_stat = 0xff;

memset(sm_zero, 0, sizeof(sm_zero));
memset(fmmu_zero, 0, sizeof(fmmu_zero));

printf("%d slaves found and configured.\n",ec_slavecount);

/* wait for all slaves to reach PRE_OP state */
ec_statecheck(0, EC_STATE_PRE_OP, EC_TIMEOUTSTATE * 4);
counter = 3;
do {
/* wait for slave to reach PREOP state */
if (ec_statecheck(slave, EC_STATE_PRE_OP, EC_TIMEOUTSTATE * 4) == EC_STATE_PRE_OP) {
printf("Slave is in PREOP state\n");
counter = 0;
}
}
while (counter-- > 0);

printf("Request init state for slave %d\n", slave);
ec_slave[slave].state = EC_STATE_INIT;
ec_writestate(slave);
counter = 3;
do {
printf("Request init state for slave %d\n", slave);
ec_slave[slave].state = EC_STATE_INIT;
ec_writestate(slave);

/* wait for slave to reach INIT state */
if (ec_statecheck(slave, EC_STATE_INIT, EC_TIMEOUTSTATE * 4) == EC_STATE_INIT) {
counter = 0;
}
}
while (counter-- > 0);
printf("Slave %d state to INIT. counter: %d\n", slave, counter);

/* wait for slave to reach INIT state */
ec_statecheck(slave, EC_STATE_INIT, EC_TIMEOUTSTATE * 4);
printf("Slave %d state to INIT.\n", slave);
/* clean FMMUs */
ec_FPWR(ec_slave[slave].configadr, ECT_REG_FMMU0, sizeof(fmmu_zero), fmmu_zero, EC_TIMEOUTRET3);
ec_FPWR(ec_slave[slave].configadr, ECT_REG_FMMU1, sizeof(fmmu_zero), fmmu_zero, EC_TIMEOUTRET3);

/* clean all SM0 / SM1 to set new bootstrap values later */
ec_FPWR(ec_slave[slave].configadr, ECT_REG_SM0, sizeof(ec_smt) * 2, sm_zero, EC_TIMEOUTRET3);
ec_FPRD(ec_slave[slave].configadr, ECT_REG_SM1STAT, 1, &rd_stat, EC_TIMEOUTRET3);
printf("Read back Status of SM1: %02x\n", rd_stat);

/* read BOOT mailbox data, master -> slave */
data = ec_readeeprom(slave, ECT_SII_BOOTRXMBX, EC_TIMEOUTEEP);
Expand Down Expand Up @@ -101,9 +132,23 @@ void boottest(char *ifname, uint16 slave, char *filename)
/* program SM1 mailbox out for slave */
ec_FPWR (ec_slave[slave].configadr, ECT_REG_SM1, sizeof(ec_smt), &ec_slave[slave].SM[1], EC_TIMEOUTRET);

printf("Request BOOT state for slave %d\n", slave);
ec_slave[slave].state = EC_STATE_BOOT;
ec_writestate(slave);
/* give EEPROM control to PDI */
rd_stat = 1;
ec_FPWR (ec_slave[slave].configadr, ECT_REG_EEPCFG, 1, &rd_stat, EC_TIMEOUTRET);

counter = 3;
do {
uint16 ret;
printf("Request BOOT state for slave %d\n", slave);
ec_slave[slave].state = EC_STATE_BOOT;
printf("ec_writestate returned: %d\n", ec_writestate(slave));
ret = ec_statecheck(slave, EC_STATE_BOOT, EC_TIMEOUTSTATE );
printf("ec_statecheck returned: %d\n", ret);
if (ret == EC_STATE_BOOT)
counter = 0;
} while(counter-- > 0);

printf("check BOOT state again\n");

/* wait for slave to reach BOOT state */
if (ec_statecheck(slave, EC_STATE_BOOT, EC_TIMEOUTSTATE * 10) == EC_STATE_BOOT)
Expand All @@ -112,22 +157,67 @@ void boottest(char *ifname, uint16 slave, char *filename)

if (input_bin(filename, &filesize))
{
char *short_filename = strrchr(filename, '/'); /* search for last / */
if (short_filename)
short_filename++; /* jump over the \ */
else
short_filename = filename; /* no \ found -> must be a short filename */
printf("File read OK, %d bytes.\n",filesize);
printf("FoE write....");
j = ec_FOEwrite(slave, filename, 0, filesize , &filebuffer, EC_TIMEOUTSTATE);
printf("FoE write %s....\n", short_filename);
j = ec_FOEwrite(slave, short_filename, 0, filesize , &filebuffer, EC_TIMEOUTSTATE);
printf("result %d.\n",j);
printf("Request init state for slave %d\n", slave);
ec_slave[slave].state = EC_STATE_INIT;
ec_writestate(slave);
if (j == 0) retval = 5;
else if (j != 1) retval = j;

if (retval == 0) {
/* wait max 600s => 10 minutes for firmware update to complete */
counter = 60;
retval = 6; /* only success switch to init state afterwards completes firmware update */
do {
uint16 ret;
printf("Request init state for slave %d (counter: %d)\n", slave, counter);
ec_slave[slave].state = EC_STATE_INIT;
ec_writestate(slave);
ret = ec_statecheck(slave, EC_STATE_INIT, 10000000);
if (ret == 0) {
int count;
if ((count = ec_config_init(FALSE)) >= slave) {
ec_slave[slave].state = EC_STATE_INIT;
ec_writestate(slave);
ret = ec_statecheck(slave, EC_STATE_INIT, EC_TIMEOUTSTATE * 10);
}
else {
printf("Slaves found: %d Needed: %d .. will try it again\n", count, slave);
#ifndef WIN32
sleep(10);
#endif
ret = 25555;
}
}
if (ret == EC_STATE_INIT) {
counter = 0;
printf("State change to init success\n");
retval = 0;
}
} while (counter-- > 0);
}
}
else
printf("File not read OK.\n");
{
printf("File not read OK.\n");
retval = 4;
}
}
else {
printf("Failed to enter boot mode\n");
retval = 3;
}

}
else
{
printf("No slaves found!\n");
retval = 2;
}
printf("End firmware update example, close socket\n");
/* stop SOEM, close socket */
Expand All @@ -136,17 +226,20 @@ void boottest(char *ifname, uint16 slave, char *filename)
else
{
printf("No socket connection on %s\nExcecute as root\n",ifname);
retval = 1;
}
return retval;
}

int main(int argc, char *argv[])
{
int ret = 0;
printf("SOEM (Simple Open EtherCAT Master)\nFirmware update example\n");

if (argc > 3)
{
argslave = atoi(argv[2]);
boottest(argv[1], argslave, argv[3]);
ret = boottest(argv[1], argslave, argv[3]);
}
else
{
Expand All @@ -158,5 +251,5 @@ int main(int argc, char *argv[])
}

printf("End program\n");
return (0);
return ret;
}