AB&T / SOEM

Dependents:   EasyCAT_LAB_simple EasyCAT_LAB_very_simple EasyCAT_LAB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ethercatfoe.c Source File

ethercatfoe.c

Go to the documentation of this file.
00001 /*
00002  * Licensed under the GNU General Public License version 2 with exceptions. See
00003  * LICENSE file in the project root for full license information
00004  */
00005 
00006 /** \file
00007  * \brief
00008  * File over EtherCAT (FoE) module.
00009  *
00010  * SDO read / write and SDO service functions
00011  */
00012 
00013 #include <stdio.h>
00014 #include <string.h>
00015 #include "osal.h"
00016 #include "oshw.h"
00017 #include "ethercattype.h"
00018 #include "ethercatbase.h"
00019 #include "ethercatmain.h"
00020 #include "ethercatfoe.h"
00021 
00022 #define EC_MAXFOEDATA 512
00023 
00024 /** FOE structure.
00025  * Used for Read, Write, Data, Ack and Error mailbox packets.
00026  */
00027 PACKED_BEGIN
00028 typedef struct PACKED
00029 {
00030    ec_mbxheadert MbxHeader;
00031    uint8         OpCode;
00032    uint8         Reserved;
00033    union
00034    {
00035       uint32        Password;
00036       uint32        PacketNumber;
00037       uint32        ErrorCode;
00038    };
00039    union
00040    {
00041       char          FileName[EC_MAXFOEDATA];
00042       uint8         Data[EC_MAXFOEDATA];
00043       char          ErrorText[EC_MAXFOEDATA];
00044    };
00045 } ec_FOEt;
00046 PACKED_END
00047 
00048 /** FoE progress hook.
00049  *
00050  * @param[in]  context        = context struct
00051  * @param[in]     hook       = Pointer to hook function.
00052  * @return 1
00053  */
00054 int ecx_FOEdefinehook(ecx_contextt *context, void *hook)
00055 {
00056   context->FOEhook = hook;
00057   return 1;
00058 }
00059 
00060 /** FoE read, blocking.
00061  *
00062  * @param[in]  context        = context struct
00063  * @param[in]     slave      = Slave number.
00064  * @param[in]     filename   = Filename of file to read.
00065  * @param[in]     password   = password.
00066  * @param[in,out] psize      = Size in bytes of file buffer, returns bytes read from file.
00067  * @param[out]    p          = Pointer to file buffer
00068  * @param[in]     timeout    = Timeout per mailbox cycle in us, standard is EC_TIMEOUTRXM
00069  * @return Workcounter from last slave response
00070  */
00071 int ecx_FOEread(ecx_contextt *context, uint16 slave, char *filename, uint32 password, int *psize, void *p, int timeout)
00072 {
00073    ec_FOEt *FOEp, *aFOEp;
00074    int wkc;
00075    int32 dataread = 0;
00076    int32 buffersize, packetnumber, prevpacket = 0;
00077    uint16 fnsize, maxdata, segmentdata;
00078    ec_mbxbuft MbxIn, MbxOut;
00079    uint8 cnt;
00080    boolean worktodo;
00081 
00082    buffersize = *psize;
00083    ec_clearmbx(&MbxIn);
00084    /* Empty slave out mailbox if something is in. Timeout set to 0 */
00085    wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0);
00086    ec_clearmbx(&MbxOut);
00087    aFOEp = (ec_FOEt *)&MbxIn;
00088    FOEp = (ec_FOEt *)&MbxOut;
00089    fnsize = (uint16)strlen(filename);
00090    maxdata = context->slavelist[slave].mbx_l - 12;
00091    if (fnsize > maxdata)
00092    {
00093       fnsize = maxdata;
00094    }
00095    FOEp->MbxHeader.length = htoes(0x0006 + fnsize);
00096    FOEp->MbxHeader.address = htoes(0x0000);
00097    FOEp->MbxHeader.priority = 0x00;
00098    /* get new mailbox count value, used as session handle */
00099    cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt);
00100    context->slavelist[slave].mbx_cnt = cnt;
00101    FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + (cnt << 4); /* FoE */
00102    FOEp->OpCode = ECT_FOE_READ;
00103    FOEp->Password = htoel(password);
00104    /* copy filename in mailbox */
00105    memcpy(&FOEp->FileName[0], filename, fnsize);
00106    /* send FoE request to slave */
00107    wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
00108    if (wkc > 0) /* succeeded to place mailbox in slave ? */
00109    {
00110       do
00111       {
00112          worktodo = FALSE;
00113          /* clean mailboxbuffer */
00114          ec_clearmbx(&MbxIn);
00115          /* read slave response */
00116          wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout);
00117          if (wkc > 0) /* succeeded to read slave response ? */
00118          {
00119             /* slave response should be FoE */
00120             if ((aFOEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_FOE)
00121             {
00122                if(aFOEp->OpCode == ECT_FOE_DATA)
00123                {
00124                   segmentdata = etohs(aFOEp->MbxHeader.length) - 0x0006;
00125                   packetnumber = etohl(aFOEp->PacketNumber);
00126                   if ((packetnumber == ++prevpacket) && (dataread + segmentdata <= buffersize))
00127                   {
00128                      memcpy(p, &aFOEp->Data[0], segmentdata);
00129                      dataread += segmentdata;
00130                      p = (uint8 *)p + segmentdata;
00131                      if (segmentdata == maxdata)
00132                      {
00133                         worktodo = TRUE;
00134                      }
00135                      FOEp->MbxHeader.length = htoes(0x0006);
00136                      FOEp->MbxHeader.address = htoes(0x0000);
00137                      FOEp->MbxHeader.priority = 0x00;
00138                      /* get new mailbox count value */
00139                      cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt);
00140                      context->slavelist[slave].mbx_cnt = cnt;
00141                      FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + (cnt << 4); /* FoE */
00142                      FOEp->OpCode = ECT_FOE_ACK;
00143                      FOEp->PacketNumber = htoel(packetnumber);
00144                      /* send FoE ack to slave */
00145                      wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
00146                      if (wkc <= 0)
00147                      {
00148                         worktodo = FALSE;
00149                      }
00150                      if (context->FOEhook)
00151                      {
00152                         context->FOEhook(slave, packetnumber, dataread);
00153                      }
00154                   }
00155                   else
00156                   {
00157                      /* FoE error */
00158                      wkc = -EC_ERR_TYPE_FOE_BUF2SMALL;
00159                   }
00160                }
00161                else
00162                {
00163                   if(aFOEp->OpCode == ECT_FOE_ERROR)
00164                   {
00165                      /* FoE error */
00166                      wkc = -EC_ERR_TYPE_FOE_ERROR;
00167                   }
00168                   else
00169                   {
00170                      /* unexpected mailbox received */
00171                      wkc = -EC_ERR_TYPE_PACKET_ERROR;
00172                   }
00173                }
00174             }
00175             else
00176             {
00177                /* unexpected mailbox received */
00178                wkc = -EC_ERR_TYPE_PACKET_ERROR;
00179             }
00180             *psize = dataread;
00181          }
00182       } while (worktodo);
00183    }
00184 
00185    return wkc;
00186 }
00187 
00188 /** FoE write, blocking.
00189  *
00190  * @param[in]  context        = context struct
00191  * @param[in]  slave      = Slave number.
00192  * @param[in]  filename   = Filename of file to write.
00193  * @param[in]  password   = password.
00194  * @param[in]  psize      = Size in bytes of file buffer.
00195  * @param[out] p          = Pointer to file buffer
00196  * @param[in]  timeout    = Timeout per mailbox cycle in us, standard is EC_TIMEOUTRXM
00197  * @return Workcounter from last slave response
00198  */
00199 int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 password, int psize, void *p, int timeout)
00200 {
00201    ec_FOEt *FOEp, *aFOEp;
00202    int wkc;
00203    int32 packetnumber, sendpacket = 0;
00204    uint16 fnsize, maxdata;
00205    int segmentdata;
00206    ec_mbxbuft MbxIn, MbxOut;
00207    uint8 cnt;
00208    boolean worktodo, dofinalzero;
00209    int tsize;
00210 
00211    ec_clearmbx(&MbxIn);
00212    /* Empty slave out mailbox if something is in. Timeout set to 0 */
00213    wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0);
00214    ec_clearmbx(&MbxOut);
00215    aFOEp = (ec_FOEt *)&MbxIn;
00216    FOEp = (ec_FOEt *)&MbxOut;
00217    dofinalzero = FALSE;
00218    fnsize = (uint16)strlen(filename);
00219    maxdata = context->slavelist[slave].mbx_l - 12;
00220    if (fnsize > maxdata)
00221    {
00222       fnsize = maxdata;
00223    }
00224    FOEp->MbxHeader.length = htoes(0x0006 + fnsize);
00225    FOEp->MbxHeader.address = htoes(0x0000);
00226    FOEp->MbxHeader.priority = 0x00;
00227    /* get new mailbox count value, used as session handle */
00228    cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt);
00229    context->slavelist[slave].mbx_cnt = cnt;
00230    FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + (cnt << 4); /* FoE */
00231    FOEp->OpCode = ECT_FOE_WRITE;
00232    FOEp->Password = htoel(password);
00233    /* copy filename in mailbox */
00234    memcpy(&FOEp->FileName[0], filename, fnsize);
00235    /* send FoE request to slave */
00236    wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
00237    if (wkc > 0) /* succeeded to place mailbox in slave ? */
00238    {
00239       do
00240       {
00241          worktodo = FALSE;
00242          /* clean mailboxbuffer */
00243          ec_clearmbx(&MbxIn);
00244          /* read slave response */
00245          wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout);
00246          if (wkc > 0) /* succeeded to read slave response ? */
00247          {
00248             /* slave response should be FoE */
00249             if ((aFOEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_FOE)
00250             {
00251                switch (aFOEp->OpCode)
00252                {
00253                   case ECT_FOE_ACK:
00254                   {
00255                      packetnumber = etohl(aFOEp->PacketNumber);
00256                      if (packetnumber == sendpacket)
00257                      {
00258                         if (context->FOEhook)
00259                         {
00260                            context->FOEhook(slave, packetnumber, psize);
00261                         }
00262                         tsize = psize;
00263                         if (tsize > maxdata)
00264                         {
00265                            tsize = maxdata;
00266                         }
00267                         if(tsize || dofinalzero)
00268                         {
00269                            worktodo = TRUE;
00270                            dofinalzero = FALSE;
00271                            segmentdata = tsize;
00272                            psize -= segmentdata;
00273                            /* if last packet was full size, add a zero size packet as final */
00274                            /* EOF is defined as packetsize < full packetsize */
00275                            if (!psize && (segmentdata == maxdata))
00276                            {
00277                               dofinalzero = TRUE;
00278                            }
00279                            FOEp->MbxHeader.length = htoes(0x0006 + segmentdata);
00280                            FOEp->MbxHeader.address = htoes(0x0000);
00281                            FOEp->MbxHeader.priority = 0x00;
00282                            /* get new mailbox count value */
00283                            cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt);
00284                            context->slavelist[slave].mbx_cnt = cnt;
00285                            FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + (cnt << 4); /* FoE */
00286                            FOEp->OpCode = ECT_FOE_DATA;
00287                            sendpacket++;
00288                            FOEp->PacketNumber = htoel(sendpacket);
00289                            memcpy(&FOEp->Data[0], p, segmentdata);
00290                            p = (uint8 *)p + segmentdata;
00291                            /* send FoE data to slave */
00292                            wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
00293                            if (wkc <= 0)
00294                            {
00295                               worktodo = FALSE;
00296                            }
00297                         }
00298                      }
00299                      else
00300                      {
00301                         /* FoE error */
00302                         wkc = -EC_ERR_TYPE_FOE_PACKETNUMBER;
00303                      }
00304                      break;
00305                   }
00306                   case ECT_FOE_BUSY:
00307                   {
00308                      /* resend if data has been send before */
00309                      /* otherwise ignore */
00310                      if (sendpacket)
00311                      {
00312                         if (!psize)
00313                         {
00314                            dofinalzero = TRUE;
00315                         }
00316                         psize += segmentdata;
00317                         p = (uint8 *)p - segmentdata;
00318                         --sendpacket;
00319                      }
00320                      break;
00321                   }
00322                   case ECT_FOE_ERROR:
00323                   {
00324                      /* FoE error */
00325                      if (aFOEp->ErrorCode == 0x8001)
00326                      {
00327                         wkc = -EC_ERR_TYPE_FOE_FILE_NOTFOUND;
00328                      }
00329                      else
00330                      {
00331                         wkc = -EC_ERR_TYPE_FOE_ERROR;
00332                      }
00333                      break;
00334                   }
00335                   default:
00336                   {
00337                      /* unexpected mailbox received */
00338                      wkc = -EC_ERR_TYPE_PACKET_ERROR;
00339                      break;
00340                   }
00341                }
00342             }
00343             else
00344             {
00345                /* unexpected mailbox received */
00346                wkc = -EC_ERR_TYPE_PACKET_ERROR;
00347             }
00348          }
00349       } while (worktodo);
00350    }
00351 
00352    return wkc;
00353 }
00354 
00355 #ifdef EC_VER1
00356 int ec_FOEdefinehook(void *hook)
00357 {
00358    return ecx_FOEdefinehook(&ecx_context, hook);
00359 }
00360 
00361 int ec_FOEread(uint16 slave, char *filename, uint32 password, int *psize, void *p, int timeout)
00362 {
00363    return ecx_FOEread(&ecx_context, slave, filename, password, psize, p, timeout);
00364 }
00365 
00366 int ec_FOEwrite(uint16 slave, char *filename, uint32 password, int psize, void *p, int timeout)
00367 {
00368    return ecx_FOEwrite(&ecx_context, slave, filename, password, psize, p, timeout);
00369 }
00370 #endif