Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: EasyCAT_LAB_simple EasyCAT_LAB_very_simple EasyCAT_LAB
ethercatfoe.c
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
Generated on Tue Jul 12 2022 18:21:13 by
