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
ethercatmain.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 /** 00007 * \file 00008 * \brief 00009 * Main EtherCAT functions. 00010 * 00011 * Initialisation, state set and read, mailbox primitives, EEPROM primitives, 00012 * SII reading and processdata exchange. 00013 * 00014 * Defines ec_slave[]. All slave information is put in this structure. 00015 * Needed for most user interaction with slaves. 00016 */ 00017 00018 #include <stdio.h> 00019 #include <string.h> 00020 #include "osal.h" 00021 #include "oshw.h" 00022 #include "ethercat.h" 00023 00024 00025 /** delay in us for eeprom ready loop */ 00026 #define EC_LOCALDELAY 200 00027 00028 /** record for ethercat eeprom communications */ 00029 PACKED_BEGIN 00030 typedef struct PACKED 00031 { 00032 uint16 comm; 00033 uint16 addr; 00034 uint16 d2; 00035 } ec_eepromt; 00036 PACKED_END 00037 00038 /** mailbox error structure */ 00039 PACKED_BEGIN 00040 typedef struct PACKED 00041 { 00042 ec_mbxheadert MbxHeader; 00043 uint16 Type; 00044 uint16 Detail; 00045 } ec_mbxerrort; 00046 PACKED_END 00047 00048 /** emergency request structure */ 00049 PACKED_BEGIN 00050 typedef struct PACKED 00051 { 00052 ec_mbxheadert MbxHeader; 00053 uint16 CANOpen; 00054 uint16 ErrorCode; 00055 uint8 ErrorReg; 00056 uint8 bData; 00057 uint16 w1,w2; 00058 } ec_emcyt; 00059 PACKED_END 00060 00061 #ifdef EC_VER1 00062 /** Main slave data array. 00063 * Each slave found on the network gets its own record. 00064 * ec_slave[0] is reserved for the master. Structure gets filled 00065 * in by the configuration function ec_config(). 00066 */ 00067 ec_slavet ec_slave[EC_MAXSLAVE]; 00068 /** number of slaves found on the network */ 00069 int ec_slavecount; 00070 /** slave group structure */ 00071 ec_groupt ec_group[EC_MAXGROUP]; 00072 00073 /** cache for EEPROM read functions */ 00074 static uint8 ec_esibuf[EC_MAXEEPBUF]; 00075 /** bitmap for filled cache buffer bytes */ 00076 static uint32 ec_esimap[EC_MAXEEPBITMAP]; 00077 /** current slave for EEPROM cache buffer */ 00078 static ec_eringt ec_elist; 00079 static ec_idxstackT ec_idxstack; 00080 00081 /** SyncManager Communication Type struct to store data of one slave */ 00082 static ec_SMcommtypet ec_SMcommtype[EC_MAX_MAPT]; 00083 /** PDO assign struct to store data of one slave */ 00084 static ec_PDOassignt ec_PDOassign[EC_MAX_MAPT]; 00085 /** PDO description struct to store data of one slave */ 00086 static ec_PDOdesct ec_PDOdesc[EC_MAX_MAPT]; 00087 00088 /** buffer for EEPROM SM data */ 00089 static ec_eepromSMt ec_SM; 00090 /** buffer for EEPROM FMMU data */ 00091 static ec_eepromFMMUt ec_FMMU; 00092 /** Global variable TRUE if error available in error stack */ 00093 boolean EcatError = FALSE; 00094 00095 int64 ec_DCtime; 00096 00097 ecx_portt ecx_port; 00098 ecx_redportt ecx_redport; 00099 00100 ecx_contextt ecx_context = { 00101 &ecx_port, // .port = 00102 &ec_slave[0], // .slavelist = 00103 &ec_slavecount, // .slavecount = 00104 EC_MAXSLAVE, // .maxslave = 00105 &ec_group[0], // .grouplist = 00106 EC_MAXGROUP, // .maxgroup = 00107 &ec_esibuf[0], // .esibuf = 00108 &ec_esimap[0], // .esimap = 00109 0, // .esislave = 00110 &ec_elist, // .elist = 00111 &ec_idxstack, // .idxstack = 00112 &EcatError, // .ecaterror = 00113 0, // .DCtO = 00114 0, // .DCl = 00115 &ec_DCtime, // .DCtime = 00116 &ec_SMcommtype[0], // .SMcommtype = 00117 &ec_PDOassign[0], // .PDOassign = 00118 &ec_PDOdesc[0], // .PDOdesc = 00119 &ec_SM, // .eepSM = 00120 &ec_FMMU, // .eepFMMU = 00121 NULL, // .FOEhook() 00122 NULL // .EOEhook() 00123 }; 00124 #endif 00125 00126 /** Create list over available network adapters. 00127 * 00128 * @return First element in list over available network adapters. 00129 */ 00130 ec_adaptert * ec_find_adapters (void) 00131 { 00132 ec_adaptert * ret_adapter; 00133 00134 ret_adapter = oshw_find_adapters (); 00135 00136 return ret_adapter; 00137 } 00138 00139 /** Free dynamically allocated list over available network adapters. 00140 * 00141 * @param[in] adapter = Struct holding adapter name, description and pointer to next. 00142 */ 00143 void ec_free_adapters (ec_adaptert * adapter) 00144 { 00145 oshw_free_adapters (adapter); 00146 } 00147 00148 /** Pushes an error on the error list. 00149 * 00150 * @param[in] context = context struct 00151 * @param[in] Ec pointer describing the error. 00152 */ 00153 void ecx_pusherror(ecx_contextt *context, const ec_errort *Ec) 00154 { 00155 context->elist->Error[context->elist->head] = *Ec; 00156 context->elist->Error[context->elist->head].Signal = TRUE; 00157 context->elist->head++; 00158 if (context->elist->head > EC_MAXELIST) 00159 { 00160 context->elist->head = 0; 00161 } 00162 if (context->elist->head == context->elist->tail) 00163 { 00164 context->elist->tail++; 00165 } 00166 if (context->elist->tail > EC_MAXELIST) 00167 { 00168 context->elist->tail = 0; 00169 } 00170 *(context->ecaterror) = TRUE; 00171 } 00172 00173 /** Pops an error from the list. 00174 * 00175 * @param[in] context = context struct 00176 * @param[out] Ec = Struct describing the error. 00177 * @return TRUE if an error was popped. 00178 */ 00179 boolean ecx_poperror(ecx_contextt *context, ec_errort *Ec) 00180 { 00181 boolean notEmpty = (context->elist->head != context->elist->tail); 00182 00183 *Ec = context->elist->Error[context->elist->tail]; 00184 context->elist->Error[context->elist->tail].Signal = FALSE; 00185 if (notEmpty) 00186 { 00187 context->elist->tail++; 00188 if (context->elist->tail > EC_MAXELIST) 00189 { 00190 context->elist->tail = 0; 00191 } 00192 } 00193 else 00194 { 00195 *(context->ecaterror) = FALSE; 00196 } 00197 return notEmpty; 00198 } 00199 00200 /** Check if error list has entries. 00201 * 00202 * @param[in] context = context struct 00203 * @return TRUE if error list contains entries. 00204 */ 00205 boolean ecx_iserror(ecx_contextt *context) 00206 { 00207 return (context->elist->head != context->elist->tail); 00208 } 00209 00210 /** Report packet error 00211 * 00212 * @param[in] context = context struct 00213 * @param[in] Slave = Slave number 00214 * @param[in] Index = Index that generated error 00215 * @param[in] SubIdx = Subindex that generated error 00216 * @param[in] ErrorCode = Error code 00217 */ 00218 void ecx_packeterror(ecx_contextt *context, uint16 Slave, uint16 Index, uint8 SubIdx, uint16 ErrorCode) 00219 { 00220 ec_errort Ec; 00221 00222 memset(&Ec, 0, sizeof(Ec)); 00223 Ec.Time = osal_current_time(); 00224 Ec.Slave = Slave; 00225 Ec.Index = Index; 00226 Ec.SubIdx = SubIdx; 00227 *(context->ecaterror) = TRUE; 00228 Ec.Etype = EC_ERR_TYPE_PACKET_ERROR; 00229 Ec.ErrorCode = ErrorCode; 00230 ecx_pusherror(context, &Ec); 00231 } 00232 00233 /** Report Mailbox Error 00234 * 00235 * @param[in] context = context struct 00236 * @param[in] Slave = Slave number 00237 * @param[in] Detail = Following EtherCAT specification 00238 */ 00239 static void ecx_mbxerror(ecx_contextt *context, uint16 Slave,uint16 Detail) 00240 { 00241 ec_errort Ec; 00242 00243 memset(&Ec, 0, sizeof(Ec)); 00244 Ec.Time = osal_current_time(); 00245 Ec.Slave = Slave; 00246 Ec.Index = 0; 00247 Ec.SubIdx = 0; 00248 Ec.Etype = EC_ERR_TYPE_MBX_ERROR; 00249 Ec.ErrorCode = Detail; 00250 ecx_pusherror(context, &Ec); 00251 } 00252 00253 /** Report Mailbox Emergency Error 00254 * 00255 * @param[in] context = context struct 00256 * @param[in] Slave = Slave number 00257 * @param[in] ErrorCode = Following EtherCAT specification 00258 * @param[in] ErrorReg 00259 * @param[in] b1 00260 * @param[in] w1 00261 * @param[in] w2 00262 */ 00263 static void ecx_mbxemergencyerror(ecx_contextt *context, uint16 Slave,uint16 ErrorCode,uint16 ErrorReg, 00264 uint8 b1, uint16 w1, uint16 w2) 00265 { 00266 ec_errort Ec; 00267 00268 memset(&Ec, 0, sizeof(Ec)); 00269 Ec.Time = osal_current_time(); 00270 Ec.Slave = Slave; 00271 Ec.Index = 0; 00272 Ec.SubIdx = 0; 00273 Ec.Etype = EC_ERR_TYPE_EMERGENCY; 00274 Ec.ErrorCode = ErrorCode; 00275 Ec.ErrorReg = (uint8)ErrorReg; 00276 Ec.b1 = b1; 00277 Ec.w1 = w1; 00278 Ec.w2 = w2; 00279 ecx_pusherror(context, &Ec); 00280 } 00281 00282 /** Initialise lib in single NIC mode 00283 * @param[in] context = context struct 00284 * @param[in] ifname = Dev name, f.e. "eth0" 00285 * @return >0 if OK 00286 */ 00287 int ecx_init(ecx_contextt *context, const char * ifname) 00288 { 00289 return ecx_setupnic(context->port, ifname, FALSE); 00290 } 00291 00292 /** Initialise lib in redundant NIC mode 00293 * @param[in] context = context struct 00294 * @param[in] redport = pointer to redport, redundant port data 00295 * @param[in] ifname = Primary Dev name, f.e. "eth0" 00296 * @param[in] if2name = Secondary Dev name, f.e. "eth1" 00297 * @return >0 if OK 00298 */ 00299 int ecx_init_redundant(ecx_contextt *context, ecx_redportt *redport, const char *ifname, char *if2name) 00300 { 00301 int rval, zbuf; 00302 ec_etherheadert *ehp; 00303 00304 context->port->redport = redport; 00305 ecx_setupnic(context->port, ifname, FALSE); 00306 rval = ecx_setupnic(context->port, if2name, TRUE); 00307 /* prepare "dummy" BRD tx frame for redundant operation */ 00308 ehp = (ec_etherheadert *)&(context->port->txbuf2); 00309 ehp->sa1 = oshw_htons(secMAC[0]); 00310 zbuf = 0; 00311 ecx_setupdatagram(context->port, &(context->port->txbuf2), EC_CMD_BRD, 0, 0x0000, 0x0000, 2, &zbuf); 00312 context->port->txbuflength2 = ETH_HEADERSIZE + EC_HEADERSIZE + EC_WKCSIZE + 2; 00313 00314 return rval; 00315 } 00316 00317 /** Close lib. 00318 * @param[in] context = context struct 00319 */ 00320 void ecx_close(ecx_contextt *context) 00321 { 00322 ecx_closenic(context->port); 00323 }; 00324 00325 /** Read one byte from slave EEPROM via cache. 00326 * If the cache location is empty then a read request is made to the slave. 00327 * Depending on the slave capabilities the request is 4 or 8 bytes. 00328 * @param[in] context = context struct 00329 * @param[in] slave = slave number 00330 * @param[in] address = eeprom address in bytes (slave uses words) 00331 * @return requested byte, if not available then 0xff 00332 */ 00333 uint8 ecx_siigetbyte(ecx_contextt *context, uint16 slave, uint16 address) 00334 { 00335 uint16 configadr, eadr; 00336 uint64 edat64; 00337 uint32 edat32; 00338 uint16 mapw, mapb; 00339 int lp,cnt; 00340 uint8 retval; 00341 00342 retval = 0xff; 00343 if (slave != context->esislave) /* not the same slave? */ 00344 { 00345 memset(context->esimap, 0x00, EC_MAXEEPBITMAP * sizeof(uint32)); /* clear esibuf cache map */ 00346 context->esislave = slave; 00347 } 00348 if (address < EC_MAXEEPBUF) 00349 { 00350 mapw = address >> 5; 00351 mapb = address - (mapw << 5); 00352 if (context->esimap[mapw] & (uint32)(1 << mapb)) 00353 { 00354 /* byte is already in buffer */ 00355 retval = context->esibuf[address]; 00356 } 00357 else 00358 { 00359 /* byte is not in buffer, put it there */ 00360 configadr = context->slavelist[slave].configadr; 00361 ecx_eeprom2master(context, slave); /* set eeprom control to master */ 00362 eadr = address >> 1; 00363 edat64 = ecx_readeepromFP (context, configadr, eadr, EC_TIMEOUTEEP); 00364 /* 8 byte response */ 00365 if (context->slavelist[slave].eep_8byte) 00366 { 00367 put_unaligned64(edat64, &(context->esibuf[eadr << 1])); 00368 cnt = 8; 00369 } 00370 /* 4 byte response */ 00371 else 00372 { 00373 edat32 = (uint32)edat64; 00374 put_unaligned32(edat32, &(context->esibuf[eadr << 1])); 00375 cnt = 4; 00376 } 00377 /* find bitmap location */ 00378 mapw = eadr >> 4; 00379 mapb = (eadr << 1) - (mapw << 5); 00380 for(lp = 0 ; lp < cnt ; lp++) 00381 { 00382 /* set bitmap for each byte that is read */ 00383 context->esimap[mapw] |= (1 << mapb); 00384 mapb++; 00385 if (mapb > 31) 00386 { 00387 mapb = 0; 00388 mapw++; 00389 } 00390 } 00391 retval = context->esibuf[address]; 00392 } 00393 } 00394 00395 return retval; 00396 } 00397 00398 /** Find SII section header in slave EEPROM. 00399 * @param[in] context = context struct 00400 * @param[in] slave = slave number 00401 * @param[in] cat = section category 00402 * @return byte address of section at section length entry, if not available then 0 00403 */ 00404 int16 ecx_siifind(ecx_contextt *context, uint16 slave, uint16 cat) 00405 { 00406 int16 a; 00407 uint16 p; 00408 uint8 eectl = context->slavelist[slave].eep_pdi; 00409 00410 a = ECT_SII_START << 1; 00411 /* read first SII section category */ 00412 p = ecx_siigetbyte(context, slave, a++); 00413 p += (ecx_siigetbyte(context, slave, a++) << 8); 00414 /* traverse SII while category is not found and not EOF */ 00415 while ((p != cat) && (p != 0xffff)) 00416 { 00417 /* read section length */ 00418 p = ecx_siigetbyte(context, slave, a++); 00419 p += (ecx_siigetbyte(context, slave, a++) << 8); 00420 /* locate next section category */ 00421 a += p << 1; 00422 /* read section category */ 00423 p = ecx_siigetbyte(context, slave, a++); 00424 p += (ecx_siigetbyte(context, slave, a++) << 8); 00425 } 00426 if (p != cat) 00427 { 00428 a = 0; 00429 } 00430 if (eectl) 00431 { 00432 ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ 00433 } 00434 00435 return a; 00436 } 00437 00438 /** Get string from SII string section in slave EEPROM. 00439 * @param[in] context = context struct 00440 * @param[out] str = requested string, 0x00 if not found 00441 * @param[in] slave = slave number 00442 * @param[in] Sn = string number 00443 */ 00444 void ecx_siistring(ecx_contextt *context, char *str, uint16 slave, uint16 Sn) 00445 { 00446 uint16 a,i,j,l,n,ba; 00447 char *ptr; 00448 uint8 eectl = context->slavelist[slave].eep_pdi; 00449 00450 ptr = str; 00451 a = ecx_siifind (context, slave, ECT_SII_STRING); /* find string section */ 00452 if (a > 0) 00453 { 00454 ba = a + 2; /* skip SII section header */ 00455 n = ecx_siigetbyte(context, slave, ba++); /* read number of strings in section */ 00456 if (Sn <= n) /* is req string available? */ 00457 { 00458 for (i = 1; i <= Sn; i++) /* walk through strings */ 00459 { 00460 l = ecx_siigetbyte(context, slave, ba++); /* length of this string */ 00461 if (i < Sn) 00462 { 00463 ba += l; 00464 } 00465 else 00466 { 00467 ptr = str; 00468 for (j = 1; j <= l; j++) /* copy one string */ 00469 { 00470 if(j <= EC_MAXNAME) 00471 { 00472 *ptr = (char)ecx_siigetbyte(context, slave, ba++); 00473 ptr++; 00474 } 00475 else 00476 { 00477 ba++; 00478 } 00479 } 00480 } 00481 } 00482 *ptr = 0; /* add zero terminator */ 00483 } 00484 else 00485 { 00486 ptr = str; 00487 *ptr = 0; /* empty string */ 00488 } 00489 } 00490 if (eectl) 00491 { 00492 ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ 00493 } 00494 } 00495 00496 /** Get FMMU data from SII FMMU section in slave EEPROM. 00497 * @param[in] context = context struct 00498 * @param[in] slave = slave number 00499 * @param[out] FMMU = FMMU struct from SII, max. 4 FMMU's 00500 * @return number of FMMU's defined in section 00501 */ 00502 uint16 ecx_siiFMMU(ecx_contextt *context, uint16 slave, ec_eepromFMMUt* FMMU) 00503 { 00504 uint16 a; 00505 uint8 eectl = context->slavelist[slave].eep_pdi; 00506 00507 FMMU->nFMMU = 0; 00508 FMMU->FMMU0 = 0; 00509 FMMU->FMMU1 = 0; 00510 FMMU->FMMU2 = 0; 00511 FMMU->FMMU3 = 0; 00512 FMMU->Startpos = ecx_siifind(context, slave, ECT_SII_FMMU); 00513 00514 if (FMMU->Startpos > 0) 00515 { 00516 a = FMMU->Startpos; 00517 FMMU->nFMMU = ecx_siigetbyte(context, slave, a++); 00518 FMMU->nFMMU += (ecx_siigetbyte(context, slave, a++) << 8); 00519 FMMU->nFMMU *= 2; 00520 FMMU->FMMU0 = ecx_siigetbyte(context, slave, a++); 00521 FMMU->FMMU1 = ecx_siigetbyte(context, slave, a++); 00522 if (FMMU->nFMMU > 2) 00523 { 00524 FMMU->FMMU2 = ecx_siigetbyte(context, slave, a++); 00525 FMMU->FMMU3 = ecx_siigetbyte(context, slave, a++); 00526 } 00527 } 00528 if (eectl) 00529 { 00530 ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ 00531 } 00532 00533 return FMMU->nFMMU; 00534 } 00535 00536 /** Get SM data from SII SM section in slave EEPROM. 00537 * @param[in] context = context struct 00538 * @param[in] slave = slave number 00539 * @param[out] SM = first SM struct from SII 00540 * @return number of SM's defined in section 00541 */ 00542 uint16 ecx_siiSM(ecx_contextt *context, uint16 slave, ec_eepromSMt* SM) 00543 { 00544 uint16 a,w; 00545 uint8 eectl = context->slavelist[slave].eep_pdi; 00546 00547 SM->nSM = 0; 00548 SM->Startpos = ecx_siifind(context, slave, ECT_SII_SM); 00549 if (SM->Startpos > 0) 00550 { 00551 a = SM->Startpos; 00552 w = ecx_siigetbyte(context, slave, a++); 00553 w += (ecx_siigetbyte(context, slave, a++) << 8); 00554 SM->nSM = (w / 4); 00555 SM->PhStart = ecx_siigetbyte(context, slave, a++); 00556 SM->PhStart += (ecx_siigetbyte(context, slave, a++) << 8); 00557 SM->Plength = ecx_siigetbyte(context, slave, a++); 00558 SM->Plength += (ecx_siigetbyte(context, slave, a++) << 8); 00559 SM->Creg = ecx_siigetbyte(context, slave, a++); 00560 SM->Sreg = ecx_siigetbyte(context, slave, a++); 00561 SM->Activate = ecx_siigetbyte(context, slave, a++); 00562 SM->PDIctrl = ecx_siigetbyte(context, slave, a++); 00563 } 00564 if (eectl) 00565 { 00566 ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ 00567 } 00568 00569 return SM->nSM; 00570 } 00571 00572 /** Get next SM data from SII SM section in slave EEPROM. 00573 * @param[in] context = context struct 00574 * @param[in] slave = slave number 00575 * @param[out] SM = first SM struct from SII 00576 * @param[in] n = SM number 00577 * @return >0 if OK 00578 */ 00579 uint16 ecx_siiSMnext(ecx_contextt *context, uint16 slave, ec_eepromSMt* SM, uint16 n) 00580 { 00581 uint16 a; 00582 uint16 retVal = 0; 00583 uint8 eectl = context->slavelist[slave].eep_pdi; 00584 00585 if (n < SM->nSM) 00586 { 00587 a = SM->Startpos + 2 + (n * 8); 00588 SM->PhStart = ecx_siigetbyte(context, slave, a++); 00589 SM->PhStart += (ecx_siigetbyte(context, slave, a++) << 8); 00590 SM->Plength = ecx_siigetbyte(context, slave, a++); 00591 SM->Plength += (ecx_siigetbyte(context, slave, a++) << 8); 00592 SM->Creg = ecx_siigetbyte(context, slave, a++); 00593 SM->Sreg = ecx_siigetbyte(context, slave, a++); 00594 SM->Activate = ecx_siigetbyte(context, slave, a++); 00595 SM->PDIctrl = ecx_siigetbyte(context, slave, a++); 00596 retVal = 1; 00597 } 00598 if (eectl) 00599 { 00600 ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ 00601 } 00602 00603 return retVal; 00604 } 00605 00606 /** Get PDO data from SII PDO section in slave EEPROM. 00607 * @param[in] context = context struct 00608 * @param[in] slave = slave number 00609 * @param[out] PDO = PDO struct from SII 00610 * @param[in] t = 0=RXPDO 1=TXPDO 00611 * @return mapping size in bits of PDO 00612 */ 00613 int ecx_siiPDO(ecx_contextt *context, uint16 slave, ec_eepromPDOt* PDO, uint8 t) 00614 { 00615 uint16 a , w, c, e, er, Size; 00616 uint8 eectl = context->slavelist[slave].eep_pdi; 00617 00618 Size = 0; 00619 PDO->nPDO = 0; 00620 PDO->Length = 0; 00621 PDO->Index[1] = 0; 00622 for (c = 0 ; c < EC_MAXSM ; c++) PDO->SMbitsize[c] = 0; 00623 if (t > 1) 00624 t = 1; 00625 PDO->Startpos = ecx_siifind(context, slave, ECT_SII_PDO + t); 00626 if (PDO->Startpos > 0) 00627 { 00628 a = PDO->Startpos; 00629 w = ecx_siigetbyte(context, slave, a++); 00630 w += (ecx_siigetbyte(context, slave, a++) << 8); 00631 PDO->Length = w; 00632 c = 1; 00633 /* traverse through all PDOs */ 00634 do 00635 { 00636 PDO->nPDO++; 00637 PDO->Index[PDO->nPDO] = ecx_siigetbyte(context, slave, a++); 00638 PDO->Index[PDO->nPDO] += (ecx_siigetbyte(context, slave, a++) << 8); 00639 PDO->BitSize[PDO->nPDO] = 0; 00640 c++; 00641 e = ecx_siigetbyte(context, slave, a++); 00642 PDO->SyncM[PDO->nPDO] = ecx_siigetbyte(context, slave, a++); 00643 a += 4; 00644 c += 2; 00645 if (PDO->SyncM[PDO->nPDO] < EC_MAXSM) /* active and in range SM? */ 00646 { 00647 /* read all entries defined in PDO */ 00648 for (er = 1; er <= e; er++) 00649 { 00650 c += 4; 00651 a += 5; 00652 PDO->BitSize[PDO->nPDO] += ecx_siigetbyte(context, slave, a++); 00653 a += 2; 00654 } 00655 PDO->SMbitsize[ PDO->SyncM[PDO->nPDO] ] += PDO->BitSize[PDO->nPDO]; 00656 Size += PDO->BitSize[PDO->nPDO]; 00657 c++; 00658 } 00659 else /* PDO deactivated because SM is 0xff or > EC_MAXSM */ 00660 { 00661 c += 4 * e; 00662 a += 8 * e; 00663 c++; 00664 } 00665 if (PDO->nPDO >= (EC_MAXEEPDO - 1)) 00666 { 00667 c = PDO->Length; /* limit number of PDO entries in buffer */ 00668 } 00669 } 00670 while (c < PDO->Length); 00671 } 00672 if (eectl) 00673 { 00674 ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ 00675 } 00676 00677 return (Size); 00678 } 00679 00680 #define MAX_FPRD_MULTI 64 00681 00682 int ecx_FPRD_multi(ecx_contextt *context, int n, uint16 *configlst, ec_alstatust *slstatlst, int timeout) 00683 { 00684 int wkc; 00685 uint8 idx; 00686 ecx_portt *port; 00687 int sldatapos[MAX_FPRD_MULTI]; 00688 int slcnt; 00689 00690 port = context->port; 00691 idx = ecx_getindex(port); 00692 slcnt = 0; 00693 ecx_setupdatagram(port, &(port->txbuf[idx]), EC_CMD_FPRD, idx, 00694 *(configlst + slcnt), ECT_REG_ALSTAT, sizeof(ec_alstatust), slstatlst + slcnt); 00695 sldatapos[slcnt] = EC_HEADERSIZE; 00696 while(++slcnt < (n - 1)) 00697 { 00698 sldatapos[slcnt] = ecx_adddatagram(port, &(port->txbuf[idx]), EC_CMD_FPRD, idx, TRUE, 00699 *(configlst + slcnt), ECT_REG_ALSTAT, sizeof(ec_alstatust), slstatlst + slcnt); 00700 } 00701 if(slcnt < n) 00702 { 00703 sldatapos[slcnt] = ecx_adddatagram(port, &(port->txbuf[idx]), EC_CMD_FPRD, idx, FALSE, 00704 *(configlst + slcnt), ECT_REG_ALSTAT, sizeof(ec_alstatust), slstatlst + slcnt); 00705 } 00706 wkc = ecx_srconfirm(port, idx, timeout); 00707 if (wkc >= 0) 00708 { 00709 for(slcnt = 0 ; slcnt < n ; slcnt++) 00710 { 00711 memcpy(slstatlst + slcnt, &(port->rxbuf[idx][sldatapos[slcnt]]), sizeof(ec_alstatust)); 00712 } 00713 } 00714 ecx_setbufstat(port, idx, EC_BUF_EMPTY); 00715 return wkc; 00716 } 00717 00718 /** Read all slave states in ec_slave. 00719 * @param[in] context = context struct 00720 * @return lowest state found 00721 */ 00722 int ecx_readstate(ecx_contextt *context) 00723 { 00724 uint16 slave, fslave, lslave, configadr, lowest, rval, bitwisestate; 00725 ec_alstatust sl[MAX_FPRD_MULTI]; 00726 uint16 slca[MAX_FPRD_MULTI]; 00727 boolean noerrorflag, allslavessamestate; 00728 boolean allslavespresent = FALSE; 00729 int wkc; 00730 00731 /* Try to establish the state of all slaves sending only one broadcast datagram. 00732 * This way a number of datagrams equal to the number of slaves will be sent only if needed.*/ 00733 rval = 0; 00734 wkc = ecx_BRD(context->port, 0, ECT_REG_ALSTAT, sizeof(rval), &rval, EC_TIMEOUTRET); 00735 00736 if(wkc >= *(context->slavecount)) 00737 { 00738 allslavespresent = TRUE; 00739 } 00740 00741 rval = etohs(rval); 00742 bitwisestate = (rval & 0x0f); 00743 00744 if ((rval & EC_STATE_ERROR) == 0) 00745 { 00746 noerrorflag = TRUE; 00747 context->slavelist[0].ALstatuscode = 0; 00748 } 00749 else 00750 { 00751 noerrorflag = FALSE; 00752 } 00753 00754 switch (bitwisestate) 00755 { 00756 case EC_STATE_INIT: 00757 case EC_STATE_PRE_OP: 00758 case EC_STATE_BOOT: 00759 case EC_STATE_SAFE_OP: 00760 case EC_STATE_OPERATIONAL: 00761 allslavessamestate = TRUE; 00762 context->slavelist[0].state = bitwisestate; 00763 break; 00764 default: 00765 allslavessamestate = FALSE; 00766 break; 00767 } 00768 00769 if (noerrorflag && allslavessamestate && allslavespresent) 00770 { 00771 /* No slave has toggled the error flag so the alstatuscode 00772 * (even if different from 0) should be ignored and 00773 * the slaves have reached the same state so the internal state 00774 * can be updated without sending any datagram. */ 00775 for (slave = 1; slave <= *(context->slavecount); slave++) 00776 { 00777 context->slavelist[slave].ALstatuscode = 0x0000; 00778 context->slavelist[slave].state = bitwisestate; 00779 } 00780 lowest = bitwisestate; 00781 } 00782 else 00783 { 00784 /* Not all slaves have the same state or at least one is in error so one datagram per slave 00785 * is needed. */ 00786 context->slavelist[0].ALstatuscode = 0; 00787 lowest = 0xff; 00788 fslave = 1; 00789 do 00790 { 00791 lslave = *(context->slavecount); 00792 if ((lslave - fslave) >= MAX_FPRD_MULTI) 00793 { 00794 lslave = fslave + MAX_FPRD_MULTI - 1; 00795 } 00796 for (slave = fslave; slave <= lslave; slave++) 00797 { 00798 const ec_alstatust zero = { 0, 0, 0 }; 00799 00800 configadr = context->slavelist[slave].configadr; 00801 slca[slave - fslave] = configadr; 00802 sl[slave - fslave] = zero; 00803 } 00804 ecx_FPRD_multi(context, (lslave - fslave) + 1, &(slca[0]), &(sl[0]), EC_TIMEOUTRET3); 00805 for (slave = fslave; slave <= lslave; slave++) 00806 { 00807 configadr = context->slavelist[slave].configadr; 00808 rval = etohs(sl[slave - fslave].alstatus); 00809 context->slavelist[slave].ALstatuscode = etohs(sl[slave - fslave].alstatuscode); 00810 if ((rval & 0xf) < lowest) 00811 { 00812 lowest = (rval & 0xf); 00813 } 00814 context->slavelist[slave].state = rval; 00815 context->slavelist[0].ALstatuscode |= context->slavelist[slave].ALstatuscode; 00816 } 00817 fslave = lslave + 1; 00818 } while (lslave < *(context->slavecount)); 00819 context->slavelist[0].state = lowest; 00820 } 00821 00822 return lowest; 00823 } 00824 00825 /** Write slave state, if slave = 0 then write to all slaves. 00826 * The function does not check if the actual state is changed. 00827 * @param[in] context = context struct 00828 * @param[in] slave = Slave number, 0 = master 00829 * @return Workcounter or EC_NOFRAME 00830 */ 00831 int ecx_writestate(ecx_contextt *context, uint16 slave) 00832 { 00833 int ret; 00834 uint16 configadr, slstate; 00835 00836 if (slave == 0) 00837 { 00838 slstate = htoes(context->slavelist[slave].state); 00839 ret = ecx_BWR(context->port, 0, ECT_REG_ALCTL, sizeof(slstate), 00840 &slstate, EC_TIMEOUTRET3); 00841 } 00842 else 00843 { 00844 configadr = context->slavelist[slave].configadr; 00845 00846 ret = ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, 00847 htoes(context->slavelist[slave].state), EC_TIMEOUTRET3); 00848 } 00849 return ret; 00850 } 00851 00852 /** Check actual slave state. 00853 * This is a blocking function. 00854 * To refresh the state of all slaves ecx_readstate()should be called 00855 * @param[in] context = context struct 00856 * @param[in] slave = Slave number, 0 = all slaves (only the "slavelist[0].state" is refreshed) 00857 * @param[in] reqstate = Requested state 00858 * @param[in] timeout = Timeout value in us 00859 * @return Requested state, or found state after timeout. 00860 */ 00861 uint16 ecx_statecheck(ecx_contextt *context, uint16 slave, uint16 reqstate, int timeout) 00862 { 00863 uint16 configadr, state, rval; 00864 ec_alstatust slstat; 00865 osal_timert timer; 00866 00867 if ( slave > *(context->slavecount) ) 00868 { 00869 return 0; 00870 } 00871 osal_timer_start(&timer, timeout); 00872 configadr = context->slavelist[slave].configadr; 00873 do 00874 { 00875 if (slave < 1) 00876 { 00877 rval = 0; 00878 ecx_BRD(context->port, 0, ECT_REG_ALSTAT, sizeof(rval), &rval , EC_TIMEOUTRET); 00879 rval = etohs(rval); 00880 } 00881 else 00882 { 00883 slstat.alstatus = 0; 00884 slstat.alstatuscode = 0; 00885 ecx_FPRD(context->port, configadr, ECT_REG_ALSTAT, sizeof(slstat), &slstat, EC_TIMEOUTRET); 00886 rval = etohs(slstat.alstatus); 00887 context->slavelist[slave].ALstatuscode = etohs(slstat.alstatuscode); 00888 } 00889 state = rval & 0x000f; /* read slave status */ 00890 if (state != reqstate) 00891 { 00892 osal_usleep(1000); 00893 } 00894 } 00895 while ((state != reqstate) && (osal_timer_is_expired(&timer) == FALSE)); 00896 context->slavelist[slave].state = rval; 00897 00898 return state; 00899 } 00900 00901 /** Get index of next mailbox counter value. 00902 * Used for Mailbox Link Layer. 00903 * @param[in] cnt = Mailbox counter value [0..7] 00904 * @return next mailbox counter value 00905 */ 00906 uint8 ec_nextmbxcnt(uint8 cnt) 00907 { 00908 cnt++; 00909 if (cnt > 7) 00910 { 00911 cnt = 1; /* wrap around to 1, not 0 */ 00912 } 00913 00914 return cnt; 00915 } 00916 00917 /** Clear mailbox buffer. 00918 * @param[out] Mbx = Mailbox buffer to clear 00919 */ 00920 void ec_clearmbx(ec_mbxbuft *Mbx) 00921 { 00922 memset(Mbx, 0x00, EC_MAXMBX); 00923 } 00924 00925 /** Check if IN mailbox of slave is empty. 00926 * @param[in] context = context struct 00927 * @param[in] slave = Slave number 00928 * @param[in] timeout = Timeout in us 00929 * @return >0 is success 00930 */ 00931 int ecx_mbxempty(ecx_contextt *context, uint16 slave, int timeout) 00932 { 00933 uint16 configadr; 00934 uint8 SMstat; 00935 int wkc; 00936 osal_timert timer; 00937 00938 osal_timer_start(&timer, timeout); 00939 configadr = context->slavelist[slave].configadr; 00940 do 00941 { 00942 SMstat = 0; 00943 wkc = ecx_FPRD(context->port, configadr, ECT_REG_SM0STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET); 00944 SMstat = etohs(SMstat); 00945 if (((SMstat & 0x08) != 0) && (timeout > EC_LOCALDELAY)) 00946 { 00947 osal_usleep(EC_LOCALDELAY); 00948 } 00949 } 00950 while (((wkc <= 0) || ((SMstat & 0x08) != 0)) && (osal_timer_is_expired(&timer) == FALSE)); 00951 00952 if ((wkc > 0) && ((SMstat & 0x08) == 0)) 00953 { 00954 return 1; 00955 } 00956 00957 return 0; 00958 } 00959 00960 /** Write IN mailbox to slave. 00961 * @param[in] context = context struct 00962 * @param[in] slave = Slave number 00963 * @param[out] mbx = Mailbox data 00964 * @param[in] timeout = Timeout in us 00965 * @return Work counter (>0 is success) 00966 */ 00967 int ecx_mbxsend(ecx_contextt *context, uint16 slave,ec_mbxbuft *mbx, int timeout) 00968 { 00969 uint16 mbxwo,mbxl,configadr; 00970 int wkc; 00971 00972 wkc = 0; 00973 configadr = context->slavelist[slave].configadr; 00974 mbxl = context->slavelist[slave].mbx_l; 00975 if ((mbxl > 0) && (mbxl <= EC_MAXMBX)) 00976 { 00977 if (ecx_mbxempty(context, slave, timeout)) 00978 { 00979 mbxwo = context->slavelist[slave].mbx_wo; 00980 /* write slave in mailbox */ 00981 wkc = ecx_FPWR(context->port, configadr, mbxwo, mbxl, mbx, EC_TIMEOUTRET3); 00982 } 00983 else 00984 { 00985 wkc = 0; 00986 } 00987 } 00988 00989 return wkc; 00990 } 00991 00992 /** Read OUT mailbox from slave. 00993 * Supports Mailbox Link Layer with repeat requests. 00994 * @param[in] context = context struct 00995 * @param[in] slave = Slave number 00996 * @param[out] mbx = Mailbox data 00997 * @param[in] timeout = Timeout in us 00998 * @return Work counter (>0 is success) 00999 */ 01000 int ecx_mbxreceive(ecx_contextt *context, uint16 slave, ec_mbxbuft *mbx, int timeout) 01001 { 01002 uint16 mbxro,mbxl,configadr; 01003 int wkc=0; 01004 int wkc2; 01005 uint16 SMstat; 01006 uint8 SMcontr; 01007 ec_mbxheadert *mbxh; 01008 ec_emcyt *EMp; 01009 ec_mbxerrort *MBXEp; 01010 01011 configadr = context->slavelist[slave].configadr; 01012 mbxl = context->slavelist[slave].mbx_rl; 01013 if ((mbxl > 0) && (mbxl <= EC_MAXMBX)) 01014 { 01015 osal_timert timer; 01016 01017 osal_timer_start(&timer, timeout); 01018 wkc = 0; 01019 do /* wait for read mailbox available */ 01020 { 01021 SMstat = 0; 01022 wkc = ecx_FPRD(context->port, configadr, ECT_REG_SM1STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET); 01023 SMstat = etohs(SMstat); 01024 if (((SMstat & 0x08) == 0) && (timeout > EC_LOCALDELAY)) 01025 { 01026 osal_usleep(EC_LOCALDELAY); 01027 } 01028 } 01029 while (((wkc <= 0) || ((SMstat & 0x08) == 0)) && (osal_timer_is_expired(&timer) == FALSE)); 01030 01031 if ((wkc > 0) && ((SMstat & 0x08) > 0)) /* read mailbox available ? */ 01032 { 01033 mbxro = context->slavelist[slave].mbx_ro; 01034 mbxh = (ec_mbxheadert *)mbx; 01035 do 01036 { 01037 wkc = ecx_FPRD(context->port, configadr, mbxro, mbxl, mbx, EC_TIMEOUTRET); /* get mailbox */ 01038 if ((wkc > 0) && ((mbxh->mbxtype & 0x0f) == 0x00)) /* Mailbox error response? */ 01039 { 01040 MBXEp = (ec_mbxerrort *)mbx; 01041 ecx_mbxerror(context, slave, etohs(MBXEp->Detail)); 01042 wkc = 0; /* prevent emergency to cascade up, it is already handled. */ 01043 } 01044 else if ((wkc > 0) && ((mbxh->mbxtype & 0x0f) == ECT_MBXT_COE)) /* CoE response? */ 01045 { 01046 EMp = (ec_emcyt *)mbx; 01047 if ((etohs(EMp->CANOpen) >> 12) == 0x01) /* Emergency request? */ 01048 { 01049 ecx_mbxemergencyerror(context, slave, etohs(EMp->ErrorCode), EMp->ErrorReg, 01050 EMp->bData, etohs(EMp->w1), etohs(EMp->w2)); 01051 wkc = 0; /* prevent emergency to cascade up, it is already handled. */ 01052 } 01053 } 01054 else if ((wkc > 0) && ((mbxh->mbxtype & 0x0f) == ECT_MBXT_EOE)) /* EoE response? */ 01055 { 01056 ec_EOEt * eoembx = (ec_EOEt *)mbx; 01057 uint16 frameinfo1 = etohs(eoembx->frameinfo1); 01058 /* All non fragment data frame types are expected to be handled by 01059 * slave send/receive API if the EoE hook is set 01060 */ 01061 if (EOE_HDR_FRAME_TYPE_GET(frameinfo1) == EOE_FRAG_DATA) 01062 { 01063 if (context->EOEhook) 01064 { 01065 if (context->EOEhook(context, slave, eoembx) > 0) 01066 { 01067 /* Fragment handled by EoE hook */ 01068 wkc = 0; 01069 } 01070 } 01071 } 01072 } 01073 else 01074 { 01075 if (wkc <= 0) /* read mailbox lost */ 01076 { 01077 SMstat ^= 0x0200; /* toggle repeat request */ 01078 SMstat = htoes(SMstat); 01079 wkc2 = ecx_FPWR(context->port, configadr, ECT_REG_SM1STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET); 01080 SMstat = etohs(SMstat); 01081 do /* wait for toggle ack */ 01082 { 01083 wkc2 = ecx_FPRD(context->port, configadr, ECT_REG_SM1CONTR, sizeof(SMcontr), &SMcontr, EC_TIMEOUTRET); 01084 } while (((wkc2 <= 0) || ((SMcontr & 0x02) != (HI_BYTE(SMstat) & 0x02))) && (osal_timer_is_expired(&timer) == FALSE)); 01085 do /* wait for read mailbox available */ 01086 { 01087 wkc2 = ecx_FPRD(context->port, configadr, ECT_REG_SM1STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET); 01088 SMstat = etohs(SMstat); 01089 if (((SMstat & 0x08) == 0) && (timeout > EC_LOCALDELAY)) 01090 { 01091 osal_usleep(EC_LOCALDELAY); 01092 } 01093 } while (((wkc2 <= 0) || ((SMstat & 0x08) == 0)) && (osal_timer_is_expired(&timer) == FALSE)); 01094 } 01095 } 01096 } while ((wkc <= 0) && (osal_timer_is_expired(&timer) == FALSE)); /* if WKC<=0 repeat */ 01097 } 01098 else /* no read mailbox available */ 01099 { 01100 wkc = 0; 01101 } 01102 } 01103 01104 return wkc; 01105 } 01106 01107 /** Dump complete EEPROM data from slave in buffer. 01108 * @param[in] context = context struct 01109 * @param[in] slave = Slave number 01110 * @param[out] esibuf = EEPROM data buffer, make sure it is big enough. 01111 */ 01112 void ecx_esidump(ecx_contextt *context, uint16 slave, uint8 *esibuf) 01113 { 01114 int address, incr; 01115 uint16 configadr; 01116 uint64 *p64; 01117 uint16 *p16; 01118 uint64 edat; 01119 uint8 eectl = context->slavelist[slave].eep_pdi; 01120 01121 ecx_eeprom2master(context, slave); /* set eeprom control to master */ 01122 configadr = context->slavelist[slave].configadr; 01123 address = ECT_SII_START; 01124 p16=(uint16*)esibuf; 01125 if (context->slavelist[slave].eep_8byte) 01126 { 01127 incr = 4; 01128 } 01129 else 01130 { 01131 incr = 2; 01132 } 01133 do 01134 { 01135 edat = ecx_readeepromFP(context, configadr, address, EC_TIMEOUTEEP); 01136 p64 = (uint64*)p16; 01137 *p64 = edat; 01138 p16 += incr; 01139 address += incr; 01140 } while ((address <= (EC_MAXEEPBUF >> 1)) && ((uint32)edat != 0xffffffff)); 01141 01142 if (eectl) 01143 { 01144 ecx_eeprom2pdi(context, slave); /* if eeprom control was previously pdi then restore */ 01145 } 01146 } 01147 01148 /** Read EEPROM from slave bypassing cache. 01149 * @param[in] context = context struct 01150 * @param[in] slave = Slave number 01151 * @param[in] eeproma = (WORD) Address in the EEPROM 01152 * @param[in] timeout = Timeout in us. 01153 * @return EEPROM data 32bit 01154 */ 01155 uint32 ecx_readeeprom(ecx_contextt *context, uint16 slave, uint16 eeproma, int timeout) 01156 { 01157 uint16 configadr; 01158 01159 ecx_eeprom2master(context, slave); /* set eeprom control to master */ 01160 configadr = context->slavelist[slave].configadr; 01161 01162 return ((uint32)ecx_readeepromFP(context, configadr, eeproma, timeout)); 01163 } 01164 01165 /** Write EEPROM to slave bypassing cache. 01166 * @param[in] context = context struct 01167 * @param[in] slave = Slave number 01168 * @param[in] eeproma = (WORD) Address in the EEPROM 01169 * @param[in] data = 16bit data 01170 * @param[in] timeout = Timeout in us. 01171 * @return >0 if OK 01172 */ 01173 int ecx_writeeeprom(ecx_contextt *context, uint16 slave, uint16 eeproma, uint16 data, int timeout) 01174 { 01175 uint16 configadr; 01176 01177 ecx_eeprom2master(context, slave); /* set eeprom control to master */ 01178 configadr = context->slavelist[slave].configadr; 01179 return (ecx_writeeepromFP(context, configadr, eeproma, data, timeout)); 01180 } 01181 01182 /** Set eeprom control to master. Only if set to PDI. 01183 * @param[in] context = context struct 01184 * @param[in] slave = Slave number 01185 * @return >0 if OK 01186 */ 01187 int ecx_eeprom2master(ecx_contextt *context, uint16 slave) 01188 { 01189 int wkc = 1, cnt = 0; 01190 uint16 configadr; 01191 uint8 eepctl; 01192 01193 if ( context->slavelist[slave].eep_pdi ) 01194 { 01195 configadr = context->slavelist[slave].configadr; 01196 eepctl = 2; 01197 do 01198 { 01199 wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* force Eeprom from PDI */ 01200 } 01201 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01202 eepctl = 0; 01203 cnt = 0; 01204 do 01205 { 01206 wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to master */ 01207 } 01208 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01209 context->slavelist[slave].eep_pdi = 0; 01210 } 01211 01212 return wkc; 01213 } 01214 01215 /** Set eeprom control to PDI. Only if set to master. 01216 * @param[in] context = context struct 01217 * @param[in] slave = Slave number 01218 * @return >0 if OK 01219 */ 01220 int ecx_eeprom2pdi(ecx_contextt *context, uint16 slave) 01221 { 01222 int wkc = 1, cnt = 0; 01223 uint16 configadr; 01224 uint8 eepctl; 01225 01226 if ( !context->slavelist[slave].eep_pdi ) 01227 { 01228 configadr = context->slavelist[slave].configadr; 01229 eepctl = 1; 01230 do 01231 { 01232 wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to PDI */ 01233 } 01234 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01235 context->slavelist[slave].eep_pdi = 1; 01236 } 01237 01238 return wkc; 01239 } 01240 01241 uint16 ecx_eeprom_waitnotbusyAP(ecx_contextt *context, uint16 aiadr,uint16 *estat, int timeout) 01242 { 01243 int wkc, cnt = 0, retval = 0; 01244 osal_timert timer; 01245 01246 osal_timer_start(&timer, timeout); 01247 do 01248 { 01249 if (cnt++) 01250 { 01251 osal_usleep(EC_LOCALDELAY); 01252 } 01253 *estat = 0; 01254 wkc=ecx_APRD(context->port, aiadr, ECT_REG_EEPSTAT, sizeof(*estat), estat, EC_TIMEOUTRET); 01255 *estat = etohs(*estat); 01256 } 01257 while (((wkc <= 0) || ((*estat & EC_ESTAT_BUSY) > 0)) && (osal_timer_is_expired(&timer) == FALSE)); /* wait for eeprom ready */ 01258 if ((*estat & EC_ESTAT_BUSY) == 0) 01259 { 01260 retval = 1; 01261 } 01262 01263 return retval; 01264 } 01265 01266 /** Read EEPROM from slave bypassing cache. APRD method. 01267 * @param[in] context = context struct 01268 * @param[in] aiadr = auto increment address of slave 01269 * @param[in] eeproma = (WORD) Address in the EEPROM 01270 * @param[in] timeout = Timeout in us. 01271 * @return EEPROM data 64bit or 32bit 01272 */ 01273 uint64 ecx_readeepromAP(ecx_contextt *context, uint16 aiadr, uint16 eeproma, int timeout) 01274 { 01275 uint16 estat; 01276 uint32 edat32; 01277 uint64 edat64; 01278 ec_eepromt ed; 01279 int wkc, cnt, nackcnt = 0; 01280 01281 edat64 = 0; 01282 edat32 = 0; 01283 if (ecx_eeprom_waitnotbusyAP(context, aiadr, &estat, timeout)) 01284 { 01285 if (estat & EC_ESTAT_EMASK) /* error bits are set */ 01286 { 01287 estat = htoes(EC_ECMD_NOP); /* clear error bits */ 01288 wkc = ecx_APWR(context->port, aiadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET3); 01289 } 01290 01291 do 01292 { 01293 ed.comm = htoes(EC_ECMD_READ); 01294 ed.addr = htoes(eeproma); 01295 ed.d2 = 0x0000; 01296 cnt = 0; 01297 do 01298 { 01299 wkc = ecx_APWR(context->port, aiadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET); 01300 } 01301 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01302 if (wkc) 01303 { 01304 osal_usleep(EC_LOCALDELAY); 01305 estat = 0x0000; 01306 if (ecx_eeprom_waitnotbusyAP(context, aiadr, &estat, timeout)) 01307 { 01308 if (estat & EC_ESTAT_NACK) 01309 { 01310 nackcnt++; 01311 osal_usleep(EC_LOCALDELAY * 5); 01312 } 01313 else 01314 { 01315 nackcnt = 0; 01316 if (estat & EC_ESTAT_R64) 01317 { 01318 cnt = 0; 01319 do 01320 { 01321 wkc = ecx_APRD(context->port, aiadr, ECT_REG_EEPDAT, sizeof(edat64), &edat64, EC_TIMEOUTRET); 01322 } 01323 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01324 } 01325 else 01326 { 01327 cnt = 0; 01328 do 01329 { 01330 wkc = ecx_APRD(context->port, aiadr, ECT_REG_EEPDAT, sizeof(edat32), &edat32, EC_TIMEOUTRET); 01331 } 01332 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01333 edat64=(uint64)edat32; 01334 } 01335 } 01336 } 01337 } 01338 } 01339 while ((nackcnt > 0) && (nackcnt < 3)); 01340 } 01341 01342 return edat64; 01343 } 01344 01345 /** Write EEPROM to slave bypassing cache. APWR method. 01346 * @param[in] context = context struct 01347 * @param[in] aiadr = configured address of slave 01348 * @param[in] eeproma = (WORD) Address in the EEPROM 01349 * @param[in] data = 16bit data 01350 * @param[in] timeout = Timeout in us. 01351 * @return >0 if OK 01352 */ 01353 int ecx_writeeepromAP(ecx_contextt *context, uint16 aiadr, uint16 eeproma, uint16 data, int timeout) 01354 { 01355 uint16 estat; 01356 ec_eepromt ed; 01357 int wkc, rval = 0, cnt = 0, nackcnt = 0; 01358 01359 if (ecx_eeprom_waitnotbusyAP(context, aiadr, &estat, timeout)) 01360 { 01361 if (estat & EC_ESTAT_EMASK) /* error bits are set */ 01362 { 01363 estat = htoes(EC_ECMD_NOP); /* clear error bits */ 01364 wkc = ecx_APWR(context->port, aiadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET3); 01365 } 01366 do 01367 { 01368 cnt = 0; 01369 do 01370 { 01371 wkc = ecx_APWR(context->port, aiadr, ECT_REG_EEPDAT, sizeof(data), &data, EC_TIMEOUTRET); 01372 } 01373 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01374 01375 ed.comm = EC_ECMD_WRITE; 01376 ed.addr = eeproma; 01377 ed.d2 = 0x0000; 01378 cnt = 0; 01379 do 01380 { 01381 wkc = ecx_APWR(context->port, aiadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET); 01382 } 01383 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01384 if (wkc) 01385 { 01386 osal_usleep(EC_LOCALDELAY * 2); 01387 estat = 0x0000; 01388 if (ecx_eeprom_waitnotbusyAP(context, aiadr, &estat, timeout)) 01389 { 01390 if (estat & EC_ESTAT_NACK) 01391 { 01392 nackcnt++; 01393 osal_usleep(EC_LOCALDELAY * 5); 01394 } 01395 else 01396 { 01397 nackcnt = 0; 01398 rval = 1; 01399 } 01400 } 01401 } 01402 01403 } 01404 while ((nackcnt > 0) && (nackcnt < 3)); 01405 } 01406 01407 return rval; 01408 } 01409 01410 uint16 ecx_eeprom_waitnotbusyFP(ecx_contextt *context, uint16 configadr,uint16 *estat, int timeout) 01411 { 01412 int wkc, cnt = 0, retval = 0; 01413 osal_timert timer; 01414 01415 osal_timer_start(&timer, timeout); 01416 do 01417 { 01418 if (cnt++) 01419 { 01420 osal_usleep(EC_LOCALDELAY); 01421 } 01422 *estat = 0; 01423 wkc=ecx_FPRD(context->port, configadr, ECT_REG_EEPSTAT, sizeof(*estat), estat, EC_TIMEOUTRET); 01424 *estat = etohs(*estat); 01425 } 01426 while (((wkc <= 0) || ((*estat & EC_ESTAT_BUSY) > 0)) && (osal_timer_is_expired(&timer) == FALSE)); /* wait for eeprom ready */ 01427 if ((*estat & EC_ESTAT_BUSY) == 0) 01428 { 01429 retval = 1; 01430 } 01431 01432 return retval; 01433 } 01434 01435 /** Read EEPROM from slave bypassing cache. FPRD method. 01436 * @param[in] context = context struct 01437 * @param[in] configadr = configured address of slave 01438 * @param[in] eeproma = (WORD) Address in the EEPROM 01439 * @param[in] timeout = Timeout in us. 01440 * @return EEPROM data 64bit or 32bit 01441 */ 01442 uint64 ecx_readeepromFP(ecx_contextt *context, uint16 configadr, uint16 eeproma, int timeout) 01443 { 01444 uint16 estat; 01445 uint32 edat32; 01446 uint64 edat64; 01447 ec_eepromt ed; 01448 int wkc, cnt, nackcnt = 0; 01449 01450 edat64 = 0; 01451 edat32 = 0; 01452 if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, timeout)) 01453 { 01454 if (estat & EC_ESTAT_EMASK) /* error bits are set */ 01455 { 01456 estat = htoes(EC_ECMD_NOP); /* clear error bits */ 01457 wkc=ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET3); 01458 } 01459 01460 do 01461 { 01462 ed.comm = htoes(EC_ECMD_READ); 01463 ed.addr = htoes(eeproma); 01464 ed.d2 = 0x0000; 01465 cnt = 0; 01466 do 01467 { 01468 wkc=ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET); 01469 } 01470 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01471 if (wkc) 01472 { 01473 osal_usleep(EC_LOCALDELAY); 01474 estat = 0x0000; 01475 if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, timeout)) 01476 { 01477 if (estat & EC_ESTAT_NACK) 01478 { 01479 nackcnt++; 01480 osal_usleep(EC_LOCALDELAY * 5); 01481 } 01482 else 01483 { 01484 nackcnt = 0; 01485 if (estat & EC_ESTAT_R64) 01486 { 01487 cnt = 0; 01488 do 01489 { 01490 wkc=ecx_FPRD(context->port, configadr, ECT_REG_EEPDAT, sizeof(edat64), &edat64, EC_TIMEOUTRET); 01491 } 01492 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01493 } 01494 else 01495 { 01496 cnt = 0; 01497 do 01498 { 01499 wkc=ecx_FPRD(context->port, configadr, ECT_REG_EEPDAT, sizeof(edat32), &edat32, EC_TIMEOUTRET); 01500 } 01501 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01502 edat64=(uint64)edat32; 01503 } 01504 } 01505 } 01506 } 01507 } 01508 while ((nackcnt > 0) && (nackcnt < 3)); 01509 } 01510 01511 return edat64; 01512 } 01513 01514 /** Write EEPROM to slave bypassing cache. FPWR method. 01515 * @param[in] context = context struct 01516 * @param[in] configadr = configured address of slave 01517 * @param[in] eeproma = (WORD) Address in the EEPROM 01518 * @param[in] data = 16bit data 01519 * @param[in] timeout = Timeout in us. 01520 * @return >0 if OK 01521 */ 01522 int ecx_writeeepromFP(ecx_contextt *context, uint16 configadr, uint16 eeproma, uint16 data, int timeout) 01523 { 01524 uint16 estat; 01525 ec_eepromt ed; 01526 int wkc, rval = 0, cnt = 0, nackcnt = 0; 01527 01528 if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, timeout)) 01529 { 01530 if (estat & EC_ESTAT_EMASK) /* error bits are set */ 01531 { 01532 estat = htoes(EC_ECMD_NOP); /* clear error bits */ 01533 wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET3); 01534 } 01535 do 01536 { 01537 cnt = 0; 01538 do 01539 { 01540 wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPDAT, sizeof(data), &data, EC_TIMEOUTRET); 01541 } 01542 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01543 ed.comm = EC_ECMD_WRITE; 01544 ed.addr = eeproma; 01545 ed.d2 = 0x0000; 01546 cnt = 0; 01547 do 01548 { 01549 wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET); 01550 } 01551 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01552 if (wkc) 01553 { 01554 osal_usleep(EC_LOCALDELAY * 2); 01555 estat = 0x0000; 01556 if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, timeout)) 01557 { 01558 if (estat & EC_ESTAT_NACK) 01559 { 01560 nackcnt++; 01561 osal_usleep(EC_LOCALDELAY * 5); 01562 } 01563 else 01564 { 01565 nackcnt = 0; 01566 rval = 1; 01567 } 01568 } 01569 } 01570 } 01571 while ((nackcnt > 0) && (nackcnt < 3)); 01572 } 01573 01574 return rval; 01575 } 01576 01577 /** Read EEPROM from slave bypassing cache. 01578 * Parallel read step 1, make request to slave. 01579 * @param[in] context = context struct 01580 * @param[in] slave = Slave number 01581 * @param[in] eeproma = (WORD) Address in the EEPROM 01582 */ 01583 void ecx_readeeprom1(ecx_contextt *context, uint16 slave, uint16 eeproma) 01584 { 01585 uint16 configadr, estat; 01586 ec_eepromt ed; 01587 int wkc, cnt = 0; 01588 01589 ecx_eeprom2master(context, slave); /* set eeprom control to master */ 01590 configadr = context->slavelist[slave].configadr; 01591 if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, EC_TIMEOUTEEP)) 01592 { 01593 if (estat & EC_ESTAT_EMASK) /* error bits are set */ 01594 { 01595 estat = htoes(EC_ECMD_NOP); /* clear error bits */ 01596 wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET3); 01597 } 01598 ed.comm = htoes(EC_ECMD_READ); 01599 ed.addr = htoes(eeproma); 01600 ed.d2 = 0x0000; 01601 do 01602 { 01603 wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET); 01604 } 01605 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01606 } 01607 } 01608 01609 /** Read EEPROM from slave bypassing cache. 01610 * Parallel read step 2, actual read from slave. 01611 * @param[in] context = context struct 01612 * @param[in] slave = Slave number 01613 * @param[in] timeout = Timeout in us. 01614 * @return EEPROM data 32bit 01615 */ 01616 uint32 ecx_readeeprom2(ecx_contextt *context, uint16 slave, int timeout) 01617 { 01618 uint16 estat, configadr; 01619 uint32 edat; 01620 int wkc, cnt = 0; 01621 01622 configadr = context->slavelist[slave].configadr; 01623 edat = 0; 01624 estat = 0x0000; 01625 if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, timeout)) 01626 { 01627 do 01628 { 01629 wkc = ecx_FPRD(context->port, configadr, ECT_REG_EEPDAT, sizeof(edat), &edat, EC_TIMEOUTRET); 01630 } 01631 while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES)); 01632 } 01633 01634 return edat; 01635 } 01636 01637 /** Push index of segmented LRD/LWR/LRW combination. 01638 * @param[in] context = context struct 01639 * @param[in] idx = Used datagram index. 01640 * @param[in] data = Pointer to process data segment. 01641 * @param[in] length = Length of data segment in bytes. 01642 */ 01643 static void ecx_pushindex(ecx_contextt *context, uint8 idx, void *data, uint16 length) 01644 { 01645 if(context->idxstack->pushed < EC_MAXBUF) 01646 { 01647 context->idxstack->idx[context->idxstack->pushed] = idx; 01648 context->idxstack->data[context->idxstack->pushed] = data; 01649 context->idxstack->length[context->idxstack->pushed] = length; 01650 context->idxstack->pushed++; 01651 } 01652 } 01653 01654 /** Pull index of segmented LRD/LWR/LRW combination. 01655 * @param[in] context = context struct 01656 * @return Stack location, -1 if stack is empty. 01657 */ 01658 static int ecx_pullindex(ecx_contextt *context) 01659 { 01660 int rval = -1; 01661 if(context->idxstack->pulled < context->idxstack->pushed) 01662 { 01663 rval = context->idxstack->pulled; 01664 context->idxstack->pulled++; 01665 } 01666 01667 return rval; 01668 } 01669 01670 /** 01671 * Clear the idx stack. 01672 * 01673 * @param context = context struct 01674 */ 01675 static void ecx_clearindex(ecx_contextt *context) { 01676 01677 context->idxstack->pushed = 0; 01678 context->idxstack->pulled = 0; 01679 01680 } 01681 01682 /** Transmit processdata to slaves. 01683 * Uses LRW, or LRD/LWR if LRW is not allowed (blockLRW). 01684 * Both the input and output processdata are transmitted. 01685 * The outputs with the actual data, the inputs have a placeholder. 01686 * The inputs are gathered with the receive processdata function. 01687 * In contrast to the base LRW function this function is non-blocking. 01688 * If the processdata does not fit in one datagram, multiple are used. 01689 * In order to recombine the slave response, a stack is used. 01690 * @param[in] context = context struct 01691 * @param[in] group = group number 01692 * @return >0 if processdata is transmitted. 01693 */ 01694 static int ecx_main_send_processdata(ecx_contextt *context, uint8 group, boolean use_overlap_io) 01695 { 01696 uint32 LogAdr; 01697 uint16 w1, w2; 01698 int length, sublength; 01699 uint8 idx; 01700 int wkc; 01701 uint8* data; 01702 boolean first=FALSE; 01703 uint16 currentsegment = 0; 01704 uint32 iomapinputoffset; 01705 01706 wkc = 0; 01707 if(context->grouplist[group].hasdc) 01708 { 01709 first = TRUE; 01710 } 01711 01712 /* For overlapping IO map use the biggest */ 01713 if(use_overlap_io == TRUE) 01714 { 01715 /* For overlap IOmap make the frame EQ big to biggest part */ 01716 length = (context->grouplist[group].Obytes > context->grouplist[group].Ibytes) ? 01717 context->grouplist[group].Obytes : context->grouplist[group].Ibytes; 01718 /* Save the offset used to compensate where to save inputs when frame returns */ 01719 iomapinputoffset = context->grouplist[group].Obytes; 01720 } 01721 else 01722 { 01723 length = context->grouplist[group].Obytes + context->grouplist[group].Ibytes; 01724 iomapinputoffset = 0; 01725 } 01726 01727 LogAdr = context->grouplist[group].logstartaddr; 01728 if(length) 01729 { 01730 01731 wkc = 1; 01732 /* LRW blocked by one or more slaves ? */ 01733 if(context->grouplist[group].blockLRW) 01734 { 01735 /* if inputs available generate LRD */ 01736 if(context->grouplist[group].Ibytes) 01737 { 01738 currentsegment = context->grouplist[group].Isegment; 01739 data = context->grouplist[group].inputs; 01740 length = context->grouplist[group].Ibytes; 01741 LogAdr += context->grouplist[group].Obytes; 01742 /* segment transfer if needed */ 01743 do 01744 { 01745 if(currentsegment == context->grouplist[group].Isegment) 01746 { 01747 sublength = context->grouplist[group].IOsegment[currentsegment++] - context->grouplist[group].Ioffset; 01748 } 01749 else 01750 { 01751 sublength = context->grouplist[group].IOsegment[currentsegment++]; 01752 } 01753 /* get new index */ 01754 idx = ecx_getindex(context->port); 01755 w1 = LO_WORD(LogAdr); 01756 w2 = HI_WORD(LogAdr); 01757 ecx_setupdatagram(context->port, &(context->port->txbuf[idx]), EC_CMD_LRD, idx, w1, w2, sublength, data); 01758 if(first) 01759 { 01760 context->DCl = sublength; 01761 /* FPRMW in second datagram */ 01762 context->DCtO = ecx_adddatagram(context->port, &(context->port->txbuf[idx]), EC_CMD_FRMW, idx, FALSE, 01763 context->slavelist[context->grouplist[group].DCnext].configadr, 01764 ECT_REG_DCSYSTIME, sizeof(int64), context->DCtime); 01765 first = FALSE; 01766 } 01767 /* send frame */ 01768 ecx_outframe_red(context->port, idx); 01769 /* push index and data pointer on stack */ 01770 ecx_pushindex(context, idx, data, sublength); 01771 length -= sublength; 01772 LogAdr += sublength; 01773 data += sublength; 01774 } while (length && (currentsegment < context->grouplist[group].nsegments)); 01775 } 01776 /* if outputs available generate LWR */ 01777 if(context->grouplist[group].Obytes) 01778 { 01779 data = context->grouplist[group].outputs; 01780 length = context->grouplist[group].Obytes; 01781 LogAdr = context->grouplist[group].logstartaddr; 01782 currentsegment = 0; 01783 /* segment transfer if needed */ 01784 do 01785 { 01786 sublength = context->grouplist[group].IOsegment[currentsegment++]; 01787 if((length - sublength) < 0) 01788 { 01789 sublength = length; 01790 } 01791 /* get new index */ 01792 idx = ecx_getindex(context->port); 01793 w1 = LO_WORD(LogAdr); 01794 w2 = HI_WORD(LogAdr); 01795 ecx_setupdatagram(context->port, &(context->port->txbuf[idx]), EC_CMD_LWR, idx, w1, w2, sublength, data); 01796 if(first) 01797 { 01798 context->DCl = sublength; 01799 /* FPRMW in second datagram */ 01800 context->DCtO = ecx_adddatagram(context->port, &(context->port->txbuf[idx]), EC_CMD_FRMW, idx, FALSE, 01801 context->slavelist[context->grouplist[group].DCnext].configadr, 01802 ECT_REG_DCSYSTIME, sizeof(int64), context->DCtime); 01803 first = FALSE; 01804 } 01805 /* send frame */ 01806 ecx_outframe_red(context->port, idx); 01807 /* push index and data pointer on stack */ 01808 ecx_pushindex(context, idx, data, sublength); 01809 length -= sublength; 01810 LogAdr += sublength; 01811 data += sublength; 01812 } while (length && (currentsegment < context->grouplist[group].nsegments)); 01813 } 01814 } 01815 /* LRW can be used */ 01816 else 01817 { 01818 if (context->grouplist[group].Obytes) 01819 { 01820 data = context->grouplist[group].outputs; 01821 } 01822 else 01823 { 01824 data = context->grouplist[group].inputs; 01825 /* Clear offset, don't compensate for overlapping IOmap if we only got inputs */ 01826 iomapinputoffset = 0; 01827 } 01828 /* segment transfer if needed */ 01829 do 01830 { 01831 sublength = context->grouplist[group].IOsegment[currentsegment++]; 01832 /* get new index */ 01833 idx = ecx_getindex(context->port); 01834 w1 = LO_WORD(LogAdr); 01835 w2 = HI_WORD(LogAdr); 01836 ecx_setupdatagram(context->port, &(context->port->txbuf[idx]), EC_CMD_LRW, idx, w1, w2, sublength, data); 01837 if(first) 01838 { 01839 context->DCl = sublength; 01840 /* FPRMW in second datagram */ 01841 context->DCtO = ecx_adddatagram(context->port, &(context->port->txbuf[idx]), EC_CMD_FRMW, idx, FALSE, 01842 context->slavelist[context->grouplist[group].DCnext].configadr, 01843 ECT_REG_DCSYSTIME, sizeof(int64), context->DCtime); 01844 first = FALSE; 01845 } 01846 /* send frame */ 01847 ecx_outframe_red(context->port, idx); 01848 /* push index and data pointer on stack. 01849 * the iomapinputoffset compensate for where the inputs are stored 01850 * in the IOmap if we use an overlapping IOmap. If a regular IOmap 01851 * is used it should always be 0. 01852 */ 01853 ecx_pushindex(context, idx, (data + iomapinputoffset), sublength); 01854 length -= sublength; 01855 LogAdr += sublength; 01856 data += sublength; 01857 } while (length && (currentsegment < context->grouplist[group].nsegments)); 01858 } 01859 } 01860 01861 return wkc; 01862 } 01863 01864 /** Transmit processdata to slaves. 01865 * Uses LRW, or LRD/LWR if LRW is not allowed (blockLRW). 01866 * Both the input and output processdata are transmitted in the overlapped IOmap. 01867 * The outputs with the actual data, the inputs replace the output data in the 01868 * returning frame. The inputs are gathered with the receive processdata function. 01869 * In contrast to the base LRW function this function is non-blocking. 01870 * If the processdata does not fit in one datagram, multiple are used. 01871 * In order to recombine the slave response, a stack is used. 01872 * @param[in] context = context struct 01873 * @param[in] group = group number 01874 * @return >0 if processdata is transmitted. 01875 */ 01876 int ecx_send_overlap_processdata_group(ecx_contextt *context, uint8 group) 01877 { 01878 return ecx_main_send_processdata(context, group, TRUE); 01879 } 01880 01881 /** Transmit processdata to slaves. 01882 * Uses LRW, or LRD/LWR if LRW is not allowed (blockLRW). 01883 * Both the input and output processdata are transmitted. 01884 * The outputs with the actual data, the inputs have a placeholder. 01885 * The inputs are gathered with the receive processdata function. 01886 * In contrast to the base LRW function this function is non-blocking. 01887 * If the processdata does not fit in one datagram, multiple are used. 01888 * In order to recombine the slave response, a stack is used. 01889 * @param[in] context = context struct 01890 * @param[in] group = group number 01891 * @return >0 if processdata is transmitted. 01892 */ 01893 int ecx_send_processdata_group(ecx_contextt *context, uint8 group) 01894 { 01895 return ecx_main_send_processdata(context, group, FALSE); 01896 } 01897 01898 /** Receive processdata from slaves. 01899 * Second part from ec_send_processdata(). 01900 * Received datagrams are recombined with the processdata with help from the stack. 01901 * If a datagram contains input processdata it copies it to the processdata structure. 01902 * @param[in] context = context struct 01903 * @param[in] group = group number 01904 * @param[in] timeout = Timeout in us. 01905 * @return Work counter. 01906 */ 01907 int ecx_receive_processdata_group(ecx_contextt *context, uint8 group, int timeout) 01908 { 01909 int pos, idx; 01910 int wkc = 0, wkc2; 01911 uint16 le_wkc = 0; 01912 int valid_wkc = 0; 01913 int64 le_DCtime; 01914 boolean first = FALSE; 01915 01916 if(context->grouplist[group].hasdc) 01917 { 01918 first = TRUE; 01919 } 01920 /* get first index */ 01921 pos = ecx_pullindex(context); 01922 /* read the same number of frames as send */ 01923 while (pos >= 0) 01924 { 01925 idx = context->idxstack->idx[pos]; 01926 wkc2 = ecx_waitinframe(context->port, context->idxstack->idx[pos], timeout); 01927 /* check if there is input data in frame */ 01928 if (wkc2 > EC_NOFRAME) 01929 { 01930 if((context->port->rxbuf[idx][EC_CMDOFFSET]==EC_CMD_LRD) || (context->port->rxbuf[idx][EC_CMDOFFSET]==EC_CMD_LRW)) 01931 { 01932 if(first) 01933 { 01934 memcpy(context->idxstack->data[pos], &(context->port->rxbuf[idx][EC_HEADERSIZE]), context->DCl); 01935 memcpy(&le_wkc, &(context->port->rxbuf[idx][EC_HEADERSIZE + context->DCl]), EC_WKCSIZE); 01936 wkc = etohs(le_wkc); 01937 memcpy(&le_DCtime, &(context->port->rxbuf[idx][context->DCtO]), sizeof(le_DCtime)); 01938 *(context->DCtime) = etohll(le_DCtime); 01939 first = FALSE; 01940 } 01941 else 01942 { 01943 /* copy input data back to process data buffer */ 01944 memcpy(context->idxstack->data[pos], &(context->port->rxbuf[idx][EC_HEADERSIZE]), context->idxstack->length[pos]); 01945 wkc += wkc2; 01946 } 01947 valid_wkc = 1; 01948 } 01949 else if(context->port->rxbuf[idx][EC_CMDOFFSET]==EC_CMD_LWR) 01950 { 01951 if(first) 01952 { 01953 memcpy(&le_wkc, &(context->port->rxbuf[idx][EC_HEADERSIZE + context->DCl]), EC_WKCSIZE); 01954 /* output WKC counts 2 times when using LRW, emulate the same for LWR */ 01955 wkc = etohs(le_wkc) * 2; 01956 memcpy(&le_DCtime, &(context->port->rxbuf[idx][context->DCtO]), sizeof(le_DCtime)); 01957 *(context->DCtime) = etohll(le_DCtime); 01958 first = FALSE; 01959 } 01960 else 01961 { 01962 /* output WKC counts 2 times when using LRW, emulate the same for LWR */ 01963 wkc += wkc2 * 2; 01964 } 01965 valid_wkc = 1; 01966 } 01967 } 01968 /* release buffer */ 01969 ecx_setbufstat(context->port, idx, EC_BUF_EMPTY); 01970 /* get next index */ 01971 pos = ecx_pullindex(context); 01972 } 01973 01974 ecx_clearindex(context); 01975 01976 /* if no frames has arrived */ 01977 if (valid_wkc == 0) 01978 { 01979 return EC_NOFRAME; 01980 } 01981 return wkc; 01982 } 01983 01984 01985 int ecx_send_processdata(ecx_contextt *context) 01986 { 01987 return ecx_send_processdata_group(context, 0); 01988 } 01989 01990 int ecx_send_overlap_processdata(ecx_contextt *context) 01991 { 01992 return ecx_send_overlap_processdata_group(context, 0); 01993 } 01994 01995 int ecx_receive_processdata(ecx_contextt *context, int timeout) 01996 { 01997 return ecx_receive_processdata_group(context, 0, timeout); 01998 } 01999 02000 #ifdef EC_VER1 02001 void ec_pusherror(const ec_errort *Ec) 02002 { 02003 ecx_pusherror(&ecx_context, Ec); 02004 } 02005 02006 boolean ec_poperror(ec_errort *Ec) 02007 { 02008 return ecx_poperror(&ecx_context, Ec); 02009 } 02010 02011 boolean ec_iserror(void) 02012 { 02013 return ecx_iserror(&ecx_context); 02014 } 02015 02016 void ec_packeterror(uint16 Slave, uint16 Index, uint8 SubIdx, uint16 ErrorCode) 02017 { 02018 ecx_packeterror(&ecx_context, Slave, Index, SubIdx, ErrorCode); 02019 } 02020 02021 /** Initialise lib in single NIC mode 02022 * @param[in] ifname = Dev name, f.e. "eth0" 02023 * @return >0 if OK 02024 * @see ecx_init 02025 */ 02026 int ec_init(const char * ifname) 02027 { 02028 return ecx_init(&ecx_context, ifname); 02029 } 02030 02031 /** Initialise lib in redundant NIC mode 02032 * @param[in] ifname = Primary Dev name, f.e. "eth0" 02033 * @param[in] if2name = Secondary Dev name, f.e. "eth1" 02034 * @return >0 if OK 02035 * @see ecx_init_redundant 02036 */ 02037 int ec_init_redundant(const char *ifname, char *if2name) 02038 { 02039 return ecx_init_redundant (&ecx_context, &ecx_redport, ifname, if2name); 02040 } 02041 02042 /** Close lib. 02043 * @see ecx_close 02044 */ 02045 void ec_close(void) 02046 { 02047 ecx_close(&ecx_context); 02048 }; 02049 02050 /** Read one byte from slave EEPROM via cache. 02051 * If the cache location is empty then a read request is made to the slave. 02052 * Depending on the slave capabillities the request is 4 or 8 bytes. 02053 * @param[in] slave = slave number 02054 * @param[in] address = eeprom address in bytes (slave uses words) 02055 * @return requested byte, if not available then 0xff 02056 * @see ecx_siigetbyte 02057 */ 02058 uint8 ec_siigetbyte(uint16 slave, uint16 address) 02059 { 02060 return ecx_siigetbyte (&ecx_context, slave, address); 02061 } 02062 02063 /** Find SII section header in slave EEPROM. 02064 * @param[in] slave = slave number 02065 * @param[in] cat = section category 02066 * @return byte address of section at section length entry, if not available then 0 02067 * @see ecx_siifind 02068 */ 02069 int16 ec_siifind(uint16 slave, uint16 cat) 02070 { 02071 return ecx_siifind (&ecx_context, slave, cat); 02072 } 02073 02074 /** Get string from SII string section in slave EEPROM. 02075 * @param[out] str = requested string, 0x00 if not found 02076 * @param[in] slave = slave number 02077 * @param[in] Sn = string number 02078 * @see ecx_siistring 02079 */ 02080 void ec_siistring(char *str, uint16 slave, uint16 Sn) 02081 { 02082 ecx_siistring(&ecx_context, str, slave, Sn); 02083 } 02084 02085 /** Get FMMU data from SII FMMU section in slave EEPROM. 02086 * @param[in] slave = slave number 02087 * @param[out] FMMU = FMMU struct from SII, max. 4 FMMU's 02088 * @return number of FMMU's defined in section 02089 * @see ecx_siiFMMU 02090 */ 02091 uint16 ec_siiFMMU(uint16 slave, ec_eepromFMMUt* FMMU) 02092 { 02093 return ecx_siiFMMU (&ecx_context, slave, FMMU); 02094 } 02095 02096 /** Get SM data from SII SM section in slave EEPROM. 02097 * @param[in] slave = slave number 02098 * @param[out] SM = first SM struct from SII 02099 * @return number of SM's defined in section 02100 * @see ecx_siiSM 02101 */ 02102 uint16 ec_siiSM(uint16 slave, ec_eepromSMt* SM) 02103 { 02104 return ecx_siiSM (&ecx_context, slave, SM); 02105 } 02106 02107 /** Get next SM data from SII SM section in slave EEPROM. 02108 * @param[in] slave = slave number 02109 * @param[out] SM = first SM struct from SII 02110 * @param[in] n = SM number 02111 * @return >0 if OK 02112 * @see ecx_siiSMnext 02113 */ 02114 uint16 ec_siiSMnext(uint16 slave, ec_eepromSMt* SM, uint16 n) 02115 { 02116 return ecx_siiSMnext (&ecx_context, slave, SM, n); 02117 } 02118 02119 /** Get PDO data from SII PDO section in slave EEPROM. 02120 * @param[in] slave = slave number 02121 * @param[out] PDO = PDO struct from SII 02122 * @param[in] t = 0=RXPDO 1=TXPDO 02123 * @return mapping size in bits of PDO 02124 * @see ecx_siiPDO 02125 */ 02126 int ec_siiPDO(uint16 slave, ec_eepromPDOt* PDO, uint8 t) 02127 { 02128 return ecx_siiPDO (&ecx_context, slave, PDO, t); 02129 } 02130 02131 /** Read all slave states in ec_slave. 02132 * @return lowest state found 02133 * @see ecx_readstate 02134 */ 02135 int ec_readstate(void) 02136 { 02137 return ecx_readstate (&ecx_context); 02138 } 02139 02140 /** Write slave state, if slave = 0 then write to all slaves. 02141 * The function does not check if the actual state is changed. 02142 * @param[in] slave = Slave number, 0 = master 02143 * @return 0 02144 * @see ecx_writestate 02145 */ 02146 int ec_writestate(uint16 slave) 02147 { 02148 return ecx_writestate(&ecx_context, slave); 02149 } 02150 02151 /** Check actual slave state. 02152 * This is a blocking function. 02153 * @param[in] slave = Slave number, 0 = all slaves 02154 * @param[in] reqstate = Requested state 02155 * @param[in] timeout = Timeout value in us 02156 * @return Requested state, or found state after timeout. 02157 * @see ecx_statecheck 02158 */ 02159 uint16 ec_statecheck(uint16 slave, uint16 reqstate, int timeout) 02160 { 02161 return ecx_statecheck (&ecx_context, slave, reqstate, timeout); 02162 } 02163 02164 /** Check if IN mailbox of slave is empty. 02165 * @param[in] slave = Slave number 02166 * @param[in] timeout = Timeout in us 02167 * @return >0 is success 02168 * @see ecx_mbxempty 02169 */ 02170 int ec_mbxempty(uint16 slave, int timeout) 02171 { 02172 return ecx_mbxempty (&ecx_context, slave, timeout); 02173 } 02174 02175 /** Write IN mailbox to slave. 02176 * @param[in] slave = Slave number 02177 * @param[out] mbx = Mailbox data 02178 * @param[in] timeout = Timeout in us 02179 * @return Work counter (>0 is success) 02180 * @see ecx_mbxsend 02181 */ 02182 int ec_mbxsend(uint16 slave,ec_mbxbuft *mbx, int timeout) 02183 { 02184 return ecx_mbxsend (&ecx_context, slave, mbx, timeout); 02185 } 02186 02187 /** Read OUT mailbox from slave. 02188 * Supports Mailbox Link Layer with repeat requests. 02189 * @param[in] slave = Slave number 02190 * @param[out] mbx = Mailbox data 02191 * @param[in] timeout = Timeout in us 02192 * @return Work counter (>0 is success) 02193 * @see ecx_mbxreceive 02194 */ 02195 int ec_mbxreceive(uint16 slave, ec_mbxbuft *mbx, int timeout) 02196 { 02197 return ecx_mbxreceive (&ecx_context, slave, mbx, timeout); 02198 } 02199 02200 /** Dump complete EEPROM data from slave in buffer. 02201 * @param[in] slave = Slave number 02202 * @param[out] esibuf = EEPROM data buffer, make sure it is big enough. 02203 * @see ecx_esidump 02204 */ 02205 void ec_esidump(uint16 slave, uint8 *esibuf) 02206 { 02207 ecx_esidump (&ecx_context, slave, esibuf); 02208 } 02209 02210 /** Read EEPROM from slave bypassing cache. 02211 * @param[in] slave = Slave number 02212 * @param[in] eeproma = (WORD) Address in the EEPROM 02213 * @param[in] timeout = Timeout in us. 02214 * @return EEPROM data 32bit 02215 * @see ecx_readeeprom 02216 */ 02217 uint32 ec_readeeprom(uint16 slave, uint16 eeproma, int timeout) 02218 { 02219 return ecx_readeeprom (&ecx_context, slave, eeproma, timeout); 02220 } 02221 02222 /** Write EEPROM to slave bypassing cache. 02223 * @param[in] slave = Slave number 02224 * @param[in] eeproma = (WORD) Address in the EEPROM 02225 * @param[in] data = 16bit data 02226 * @param[in] timeout = Timeout in us. 02227 * @return >0 if OK 02228 * @see ecx_writeeeprom 02229 */ 02230 int ec_writeeeprom(uint16 slave, uint16 eeproma, uint16 data, int timeout) 02231 { 02232 return ecx_writeeeprom (&ecx_context, slave, eeproma, data, timeout); 02233 } 02234 02235 /** Set eeprom control to master. Only if set to PDI. 02236 * @param[in] slave = Slave number 02237 * @return >0 if OK 02238 * @see ecx_eeprom2master 02239 */ 02240 int ec_eeprom2master(uint16 slave) 02241 { 02242 return ecx_eeprom2master(&ecx_context, slave); 02243 } 02244 02245 int ec_eeprom2pdi(uint16 slave) 02246 { 02247 return ecx_eeprom2pdi(&ecx_context, slave); 02248 } 02249 02250 uint16 ec_eeprom_waitnotbusyAP(uint16 aiadr,uint16 *estat, int timeout) 02251 { 02252 return ecx_eeprom_waitnotbusyAP (&ecx_context, aiadr, estat, timeout); 02253 } 02254 02255 /** Read EEPROM from slave bypassing cache. APRD method. 02256 * @param[in] aiadr = auto increment address of slave 02257 * @param[in] eeproma = (WORD) Address in the EEPROM 02258 * @param[in] timeout = Timeout in us. 02259 * @return EEPROM data 64bit or 32bit 02260 */ 02261 uint64 ec_readeepromAP(uint16 aiadr, uint16 eeproma, int timeout) 02262 { 02263 return ecx_readeepromAP (&ecx_context, aiadr, eeproma, timeout); 02264 } 02265 02266 /** Write EEPROM to slave bypassing cache. APWR method. 02267 * @param[in] aiadr = configured address of slave 02268 * @param[in] eeproma = (WORD) Address in the EEPROM 02269 * @param[in] data = 16bit data 02270 * @param[in] timeout = Timeout in us. 02271 * @return >0 if OK 02272 * @see ecx_writeeepromAP 02273 */ 02274 int ec_writeeepromAP(uint16 aiadr, uint16 eeproma, uint16 data, int timeout) 02275 { 02276 return ecx_writeeepromAP (&ecx_context, aiadr, eeproma, data, timeout); 02277 } 02278 02279 uint16 ec_eeprom_waitnotbusyFP(uint16 configadr,uint16 *estat, int timeout) 02280 { 02281 return ecx_eeprom_waitnotbusyFP (&ecx_context, configadr, estat, timeout); 02282 } 02283 02284 /** Read EEPROM from slave bypassing cache. FPRD method. 02285 * @param[in] configadr = configured address of slave 02286 * @param[in] eeproma = (WORD) Address in the EEPROM 02287 * @param[in] timeout = Timeout in us. 02288 * @return EEPROM data 64bit or 32bit 02289 * @see ecx_readeepromFP 02290 */ 02291 uint64 ec_readeepromFP(uint16 configadr, uint16 eeproma, int timeout) 02292 { 02293 return ecx_readeepromFP (&ecx_context, configadr, eeproma, timeout); 02294 } 02295 02296 /** Write EEPROM to slave bypassing cache. FPWR method. 02297 * @param[in] configadr = configured address of slave 02298 * @param[in] eeproma = (WORD) Address in the EEPROM 02299 * @param[in] data = 16bit data 02300 * @param[in] timeout = Timeout in us. 02301 * @return >0 if OK 02302 * @see ecx_writeeepromFP 02303 */ 02304 int ec_writeeepromFP(uint16 configadr, uint16 eeproma, uint16 data, int timeout) 02305 { 02306 return ecx_writeeepromFP (&ecx_context, configadr, eeproma, data, timeout); 02307 } 02308 02309 /** Read EEPROM from slave bypassing cache. 02310 * Parallel read step 1, make request to slave. 02311 * @param[in] slave = Slave number 02312 * @param[in] eeproma = (WORD) Address in the EEPROM 02313 * @see ecx_readeeprom1 02314 */ 02315 void ec_readeeprom1(uint16 slave, uint16 eeproma) 02316 { 02317 ecx_readeeprom1 (&ecx_context, slave, eeproma); 02318 } 02319 02320 /** Read EEPROM from slave bypassing cache. 02321 * Parallel read step 2, actual read from slave. 02322 * @param[in] slave = Slave number 02323 * @param[in] timeout = Timeout in us. 02324 * @return EEPROM data 32bit 02325 * @see ecx_readeeprom2 02326 */ 02327 uint32 ec_readeeprom2(uint16 slave, int timeout) 02328 { 02329 return ecx_readeeprom2 (&ecx_context, slave, timeout); 02330 } 02331 02332 /** Transmit processdata to slaves. 02333 * Uses LRW, or LRD/LWR if LRW is not allowed (blockLRW). 02334 * Both the input and output processdata are transmitted. 02335 * The outputs with the actual data, the inputs have a placeholder. 02336 * The inputs are gathered with the receive processdata function. 02337 * In contrast to the base LRW function this function is non-blocking. 02338 * If the processdata does not fit in one datagram, multiple are used. 02339 * In order to recombine the slave response, a stack is used. 02340 * @param[in] group = group number 02341 * @return >0 if processdata is transmitted. 02342 * @see ecx_send_processdata_group 02343 */ 02344 int ec_send_processdata_group(uint8 group) 02345 { 02346 return ecx_send_processdata_group (&ecx_context, group); 02347 } 02348 02349 /** Transmit processdata to slaves. 02350 * Uses LRW, or LRD/LWR if LRW is not allowed (blockLRW). 02351 * Both the input and output processdata are transmitted in the overlapped IOmap. 02352 * The outputs with the actual data, the inputs replace the output data in the 02353 * returning frame. The inputs are gathered with the receive processdata function. 02354 * In contrast to the base LRW function this function is non-blocking. 02355 * If the processdata does not fit in one datagram, multiple are used. 02356 * In order to recombine the slave response, a stack is used. 02357 * @param[in] context = context struct 02358 * @param[in] group = group number 02359 * @return >0 if processdata is transmitted. 02360 * @see ecx_send_overlap_processdata_group 02361 */ 02362 int ec_send_overlap_processdata_group(uint8 group) 02363 { 02364 return ecx_send_overlap_processdata_group(&ecx_context, group); 02365 } 02366 02367 /** Receive processdata from slaves. 02368 * Second part from ec_send_processdata(). 02369 * Received datagrams are recombined with the processdata with help from the stack. 02370 * If a datagram contains input processdata it copies it to the processdata structure. 02371 * @param[in] group = group number 02372 * @param[in] timeout = Timeout in us. 02373 * @return Work counter. 02374 * @see ecx_receive_processdata_group 02375 */ 02376 int ec_receive_processdata_group(uint8 group, int timeout) 02377 { 02378 return ecx_receive_processdata_group (&ecx_context, group, timeout); 02379 } 02380 02381 int ec_send_processdata(void) 02382 { 02383 return ec_send_processdata_group(0); 02384 } 02385 02386 int ec_send_overlap_processdata(void) 02387 { 02388 return ec_send_overlap_processdata_group(0); 02389 } 02390 02391 int ec_receive_processdata(int timeout) 02392 { 02393 return ec_receive_processdata_group(0, timeout); 02394 } 02395 #endif
Generated on Tue Jul 12 2022 18:21:13 by
