ethercatmain.c

Go to the documentation of this file.
00001 /*
00002  * Simple Open EtherCAT Master Library 
00003  *
00004  * File    : ethercatmain.c
00005  * Version : 1.2.5
00006  * Date    : 09-04-2011
00007  * Copyright (C) 2005-2011 Speciaal Machinefabriek Ketels v.o.f.
00008  * Copyright (C) 2005-2011 Arthur Ketels
00009  * Copyright (C) 2008-2009 TU/e Technische Universiteit Eindhoven 
00010  *
00011  * SOEM is free software; you can redistribute it and/or modify it under
00012  * the terms of the GNU General Public License version 2 as published by the Free
00013  * Software Foundation.
00014  *
00015  * SOEM is distributed in the hope that it will be useful, but WITHOUT ANY
00016  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
00017  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00018  * for more details.
00019  *
00020  * As a special exception, if other files instantiate templates or use macros
00021  * or inline functions from this file, or you compile this file and link it
00022  * with other works to produce a work based on this file, this file does not
00023  * by itself cause the resulting work to be covered by the GNU General Public
00024  * License. However the source code for this file must still be made available
00025  * in accordance with section (3) of the GNU General Public License.
00026  *
00027  * This exception does not invalidate any other reasons why a work based on
00028  * this file might be covered by the GNU General Public License.
00029  *
00030  * The EtherCAT Technology, the trade name and logo “EtherCAT” are the intellectual
00031  * property of, and protected by Beckhoff Automation GmbH. You can use SOEM for
00032  * the sole purpose of creating, using and/or selling or otherwise distributing
00033  * an EtherCAT network master provided that an EtherCAT Master License is obtained
00034  * from Beckhoff Automation GmbH.
00035  *
00036  * In case you did not receive a copy of the EtherCAT Master License along with
00037  * SOEM write to Beckhoff Automation GmbH, Eiserstraße 5, D-33415 Verl, Germany
00038  * (www.beckhoff.com).
00039  */
00040 
00041 /**
00042  * \file
00043  * \brief
00044  * Main EtherCAT functions.
00045  *
00046  * Initialisation, state set and read, mailbox primitives, EEPROM primitives,
00047  * SII reading and processdata exchange.
00048  *
00049  * Defines ec_slave[]. All slave information is put in this structure. 
00050  * Needed for most user interaction with slaves.
00051  */
00052 
00053 #include <stdio.h>
00054 #include <string.h>
00055 #include <sys/time.h>
00056 #include <arpa/inet.h>
00057 #include <unistd.h>
00058 #include "ethercattype.h"
00059 #include "nicdrv.h"
00060 #include "ethercatbase.h"
00061 #include "ethercatmain.h"
00062 
00063 /** delay in us for eeprom ready loop */
00064 #define EC_LOCALDELAY   200
00065 
00066 /** stack structure to store segmented LRD/LWR/LRW constructs */
00067 typedef struct
00068 {
00069   uint8   pushed;
00070   uint8   pulled;
00071   uint8   idx[EC_MAXBUF];
00072   void  *data[EC_MAXBUF];
00073   uint16  length[EC_MAXBUF];
00074 } ec_idxstackT;
00075 
00076 /** record for ethercat eeprom communications */
00077 typedef struct PACKED
00078 {
00079     uint16  comm;
00080     uint16  addr;
00081     uint16  d2;
00082 } ec_eepromt;
00083 
00084 /** ringbuf for error storage */
00085 typedef struct 
00086 {
00087     int16       head;
00088     int16       tail;
00089     ec_errort   Error[EC_MAXELIST + 1];
00090 } ec_eringt;
00091 
00092 /** emergency request structure */
00093 typedef struct
00094 {
00095     ec_mbxheadert   MbxHeader;
00096     uint16          CANOpen;
00097     uint16          ErrorCode;
00098     uint8           ErrorReg;
00099     uint8           bData;
00100     uint16          w1,w2;
00101 } ec_emcyt;
00102 
00103 /** Main slave data array.
00104  *  Each slave found on the network gets its own record.
00105  *  ec_slave[0] is reserved for the master. Structure gets filled
00106  *  in by the configuration function ec_config().
00107  */
00108 ec_slavet ec_slave[EC_MAXSLAVE];
00109 /** number of slaves found on the network */ 
00110 int     ec_slavecount;
00111 /** slave group structure */
00112 ec_groupt ec_group[EC_MAXGROUP];
00113 
00114 /** cache for EEPROM read functions */
00115 static uint8    esibuf[EC_MAXEEPBUF];
00116 /** bitmap for filled cache buffer bytes */
00117 static uint32   esimap[EC_MAXEEPBITMAP];
00118 /** current slave for EEPROM cache buffer */
00119 static uint16   esislave=0;
00120 static ec_eringt  ec_elist;
00121 static ec_idxstackT ec_idxstack;
00122 
00123 /** Global variable TRUE if error available in error stack */
00124 boolean   EcatError = FALSE;
00125 
00126 uint16 ec_DCtO;
00127 static uint16 ec_DCl;
00128 int64 ec_DCtime;
00129 
00130 /** Pushes an error on the error list.
00131  *
00132  * @param[in] Ec     Struct describing the error.
00133  */
00134 void ec_pusherror(const ec_errort *Ec)
00135 {
00136     ec_elist.Error[ec_elist.head] = *Ec;
00137     ec_elist.Error[ec_elist.head].Signal = TRUE;
00138     ec_elist.head++;
00139     if (ec_elist.head > EC_MAXELIST)
00140         ec_elist.head = 0;
00141     if (ec_elist.head == ec_elist.tail)
00142         ec_elist.tail++;
00143     if (ec_elist.tail > EC_MAXELIST)
00144         ec_elist.tail = 0;
00145   EcatError = TRUE;
00146 }
00147 
00148 /** Pops an error from the list.
00149  *
00150  * @param[out] Ec = Struct describing the error.
00151  * @return TRUE if an error was popped.
00152  */
00153 boolean ec_poperror(ec_errort *Ec)
00154 {
00155     boolean notEmpty = (ec_elist.head != ec_elist.tail);
00156 
00157     *Ec = ec_elist.Error[ec_elist.tail];
00158     ec_elist.Error[ec_elist.tail].Signal = FALSE;
00159     if (notEmpty)
00160     {
00161         ec_elist.tail++;
00162         if (ec_elist.tail > EC_MAXELIST)
00163             ec_elist.tail = 0;
00164     }
00165   else EcatError = FALSE;
00166     return notEmpty;
00167 }
00168 
00169 /** Check if error list has entries.
00170  *
00171  * @return TRUE if error list contains entries.
00172  */
00173 boolean ec_iserror(void)
00174 {
00175   return (ec_elist.head != ec_elist.tail);
00176 }
00177 
00178 /** Report packet error
00179  *
00180  * @param[in]  Slave    = Slave number
00181  * @param[in]  Index    = Index that generated error
00182  * @param[in]  SubIdx     = Subindex that generated error
00183  * @param[in]  ErrorCode  = Error code
00184  */
00185 void ec_packeterror(uint16 Slave, uint16 Index, uint8 SubIdx, uint16 ErrorCode)
00186 {
00187     ec_errort Ec;
00188 
00189   gettimeofday(&Ec.Time, 0);
00190     Ec.Slave = Slave;
00191     Ec.Index = Index;
00192     Ec.SubIdx = SubIdx;
00193     EcatError = TRUE;
00194     Ec.Etype = EC_ERR_TYPE_PACKET_ERROR;
00195     Ec.ErrorCode = ErrorCode;
00196     ec_pusherror(&Ec);
00197 }
00198 
00199 /** Report Mailbox Emergency Error
00200  *
00201  * @param[in]  Slave    = Slave number
00202  * @param[in]  ErrorCode    = Following EtherCAT specification
00203  * @param[in]  ErrorReg
00204  * @param[in]  b1
00205  * @param[in]  w1
00206  * @param[in]  w2
00207  */
00208 static void ec_mbxemergencyerror(uint16 Slave,uint16 ErrorCode,uint16 ErrorReg,
00209     uint8 b1, uint16 w1, uint16 w2)
00210 {
00211     ec_errort Ec;
00212 
00213   gettimeofday(&Ec.Time, 0);
00214     Ec.Slave = Slave;
00215     Ec.Index = 0;
00216     Ec.SubIdx = 0;
00217     Ec.Etype = EC_ERR_TYPE_EMERGENCY;
00218     Ec.ErrorCode = ErrorCode;
00219     Ec.ErrorReg = (uint8)ErrorReg;
00220     Ec.b1 = b1;
00221     Ec.w1 = w1;
00222     Ec.w2 = w2;
00223     ec_pusherror(&Ec);
00224 }
00225 
00226 /** Initialise lib in single NIC mode
00227  * @param[in] ifname   = Dev name, f.e. "eth0"
00228  * @return >0 if OK
00229  */
00230 int ec_init(const char * ifname)
00231 {
00232   return ec_setupnic(ifname, FALSE);
00233 } 
00234 
00235 /** Initialise lib in redundant NIC mode
00236  * @param[in] ifname  = Primary Dev name, f.e. "eth0"
00237  * @param[in] if2name = Secondary Dev name, f.e. "eth1"
00238  * @return >0 if OK
00239  */
00240 int ec_init_redundant(const char *ifname, const char *if2name)
00241 {
00242   int rval, zbuf;
00243   ec_etherheadert *ehp;
00244   
00245   ec_setupnic(ifname, FALSE);
00246   rval = ec_setupnic(if2name, TRUE);
00247   /* prepare "dummy" BRD tx frame for redundant operation */
00248   ehp = (ec_etherheadert *)&ec_txbuf2;
00249   ehp->sa1 = htons(secMAC[0]);
00250   zbuf = 0;
00251   ec_setupdatagram(&ec_txbuf2, EC_CMD_BRD, 0, 0x0000, 0x0000, 2, &zbuf);
00252   ec_txbuflength2 = ETH_HEADERSIZE + EC_HEADERSIZE + EC_WKCSIZE + 2;
00253   
00254   return rval;
00255 }
00256 
00257 /** Close lib.
00258  */
00259 void ec_close(void)
00260 {
00261   ec_closenic();
00262 };  
00263 
00264 /** Read one byte from slave EEPROM via cache.
00265  *  If the cache location is empty then a read request is made to the slave.
00266  *  Depending on the slave capabillities the request is 4 or 8 bytes.
00267  *  @param[in] slave   = slave number
00268  *  @param[in] address = eeprom address in bytes (slave uses words)
00269  *  @return requested byte, if not available then 0xff
00270  */
00271 uint8 ec_siigetbyte(uint16 slave, uint16 address)
00272 {
00273   uint16 configadr, eadr;
00274   uint64 edat;
00275   uint16 mapw, mapb;
00276   int lp,cnt;
00277   uint8 retval;
00278   
00279   retval = 0xff;
00280   if (slave != esislave) /* not the same slave? */
00281   { 
00282     memset(esimap,0x00,EC_MAXEEPBITMAP); /* clear esibuf cache map */
00283     esislave=slave;
00284   } 
00285   if (address < EC_MAXEEPBUF)
00286   {   
00287     mapw = address >> 5;
00288     mapb = address - (mapw << 5);
00289     if (esimap[mapw] & (uint32)(1 << mapb))
00290     {
00291       /* byte is already in buffer */
00292       retval = esibuf[address];
00293     }
00294     else
00295     {
00296       /* byte is not in buffer, put it there */
00297         configadr = ec_slave[slave].configadr;
00298       ec_eeprom2master(slave); /* set eeprom control to master */
00299       eadr = address >> 1;
00300       edat = ec_readeepromFP (configadr, eadr, EC_TIMEOUTEEP);
00301       /* 8 byte response */
00302       if (ec_slave[slave].eep_8byte)
00303       { 
00304         put_unaligned64(edat, &esibuf[eadr << 1]);
00305         cnt = 8;
00306       }
00307       /* 4 byte response */
00308       else
00309       {
00310         put_unaligned32(edat, &esibuf[eadr << 1]);
00311         cnt = 4;
00312       }
00313       /* find bitmap location */
00314       mapw = eadr >> 4;
00315       mapb = (eadr << 1) - (mapw << 5);
00316       for(lp = 0 ; lp < cnt ; lp++)
00317       {
00318         /* set bitmap for each byte that is read */
00319         esimap[mapw] |= (1 << mapb);
00320         mapb++;
00321         if (mapb > 31)
00322         {
00323           mapb = 0;
00324           mapw++;
00325         } 
00326       } 
00327       retval = esibuf[address];
00328     } 
00329   } 
00330   
00331   return retval;
00332 } 
00333 
00334 /** Find SII section header in slave EEPROM.
00335  *  @param[in] slave   = slave number
00336  *  @param[in] cat     = section category
00337  *  @return byte address of section at section length entry, if not available then 0
00338  */
00339 int16 ec_siifind(uint16 slave, uint16 cat)
00340 {
00341     int16 a;
00342   uint16 p;
00343   uint8 eectl = ec_slave[slave].eep_pdi;
00344 
00345     a = ECT_SII_START << 1;
00346   /* read first SII section category */
00347   p = ec_siigetbyte(slave, a++);
00348   p += (ec_siigetbyte(slave, a++) << 8);
00349   /* traverse SII while category is not found and not EOF */
00350     while ((p != cat) && (p != 0xffff))
00351     {
00352     /* read section length */
00353     p = ec_siigetbyte(slave, a++);
00354     p += (ec_siigetbyte(slave, a++) << 8);
00355     /* locate next section category */
00356         a += p << 1;
00357     /* read section category */
00358     p = ec_siigetbyte(slave, a++);
00359     p += (ec_siigetbyte(slave, a++) << 8);
00360     }
00361     if (p != cat)
00362         a = 0;
00363 
00364   if (eectl) ec_eeprom2pdi(slave); /* if eeprom control was previously pdi then restore */
00365 
00366   return a;
00367 }
00368 
00369 /** Get string from SII string section in slave EEPROM.
00370  *  @param[out] str = requested string, 0x00 if not found
00371  *  @param[in] slave   = slave number
00372  *  @param[in] Sn    = string number
00373  */
00374 void ec_siistring(char *str, uint16 slave, uint16 Sn)
00375 {
00376     uint16 a,i,j,l,n,ba,p;
00377     char *ptr;
00378   uint8 eectl = ec_slave[slave].eep_pdi;
00379 
00380     ptr = str;
00381     p = 0;
00382     a = ec_siifind (slave, ECT_SII_STRING); /* find string section */
00383     if (a > 0)
00384     {
00385         ba = a + 2; /* skip SII section header */
00386         n = ec_siigetbyte(slave, ba++); /* read number of strings in section */
00387         if (Sn <= n) /* is req string available? */
00388         {
00389             for (i = 1; i <= Sn; i++) /* walk through strings */
00390             {
00391                 l = ec_siigetbyte(slave, ba++); /* length of this string */
00392                 ptr = str;
00393                 for (j = 1; j <= l; j++) /* copy one string */
00394                 {
00395                     *ptr = (char)ec_siigetbyte(slave, ba++);
00396           ptr++;
00397                 }
00398             }
00399             *ptr = 0; /* add zero terminator */
00400         }
00401     else
00402     {
00403       ptr = str;
00404       *ptr = 0; /* empty string */
00405     } 
00406     }
00407   if (eectl) ec_eeprom2pdi(slave); /* if eeprom control was previously pdi then restore */
00408 }
00409 
00410 /** Get FMMU data from SII FMMU section in slave EEPROM.
00411  *  @param[in] slave   = slave number
00412  *  @param[out] FMMU   = FMMU struct from SII, max. 4 FMMU's
00413  *  @return number of FMMU's defined in section
00414  */
00415 uint16 ec_siiFMMU(uint16 slave, ec_eepromFMMUt* FMMU)
00416 {
00417   uint16  a;
00418   uint8 eectl = ec_slave[slave].eep_pdi;
00419   
00420     FMMU->nFMMU = 0;
00421     FMMU->FMMU0 = 0;
00422     FMMU->FMMU1 = 0;
00423     FMMU->FMMU2 = 0;
00424     FMMU->FMMU3 = 0;
00425     FMMU->Startpos = ec_siifind(slave, ECT_SII_FMMU);
00426 
00427     if (FMMU->Startpos > 0)
00428     {
00429     a = FMMU->Startpos;
00430         FMMU->nFMMU = ec_siigetbyte(slave, a++);
00431     FMMU->nFMMU += (ec_siigetbyte(slave, a++) << 8);
00432     FMMU->nFMMU *= 2;
00433         FMMU->FMMU0 = ec_siigetbyte(slave, a++);
00434         FMMU->FMMU1 = ec_siigetbyte(slave, a++);
00435         if (FMMU->nFMMU > 2)
00436         {
00437             FMMU->FMMU2 = ec_siigetbyte(slave, a++);
00438             FMMU->FMMU3 = ec_siigetbyte(slave, a++);
00439         }
00440     }
00441   if (eectl) ec_eeprom2pdi(slave); /* if eeprom control was previously pdi then restore */
00442     return FMMU->nFMMU;
00443 }
00444 
00445 /** Get SM data from SII SM section in slave EEPROM.
00446  *  @param[in] slave   = slave number
00447  *  @param[out] SM     = first SM struct from SII
00448  *  @return number of SM's defined in section
00449  */
00450 uint16 ec_siiSM(uint16 slave, ec_eepromSMt* SM)
00451 {
00452     uint16 a,w,l;
00453   uint8 eectl = ec_slave[slave].eep_pdi;
00454 
00455     SM->nSM = 0;
00456     l = 0;
00457     SM->Startpos = ec_siifind(slave, ECT_SII_SM);
00458     if (SM->Startpos > 0)
00459     {
00460     a = SM->Startpos;   
00461     w = ec_siigetbyte(slave, a++);
00462     w += (ec_siigetbyte(slave, a++) << 8);
00463         SM->nSM = (w / 4);
00464         SM->PhStart = ec_siigetbyte(slave, a++);
00465     SM->PhStart += (ec_siigetbyte(slave, a++) << 8);
00466         SM->Plength = ec_siigetbyte(slave, a++);
00467     SM->Plength += (ec_siigetbyte(slave, a++) << 8);
00468         SM->Creg = ec_siigetbyte(slave, a++);
00469         SM->Sreg = ec_siigetbyte(slave, a++);
00470         SM->Activate = ec_siigetbyte(slave, a++);
00471         SM->PDIctrl = ec_siigetbyte(slave, a++);
00472     }
00473   if (eectl) ec_eeprom2pdi(slave); /* if eeprom control was previously pdi then restore */
00474     return SM->nSM;
00475 }
00476 
00477 /** Get next SM data from SII SM section in slave EEPROM.
00478  *  @param[in] slave   = slave number
00479  *  @param[out] SM     = first SM struct from SII
00480  *  @param[in] n     = SM number
00481  *  @return >0 if OK
00482  */
00483 uint16 ec_siiSMnext(uint16 slave, ec_eepromSMt* SM, uint16 n)
00484 {
00485     uint16 a;
00486     uint16 retVal = 0;
00487   uint8 eectl = ec_slave[slave].eep_pdi;
00488 
00489     if (n < SM->nSM)
00490     {
00491         a = SM->Startpos + 2 + (n * 8);
00492         SM->PhStart = ec_siigetbyte(slave, a++);
00493     SM->PhStart += (ec_siigetbyte(slave, a++) << 8);
00494         SM->Plength = ec_siigetbyte(slave, a++);
00495     SM->Plength += (ec_siigetbyte(slave, a++) << 8);
00496         SM->Creg = ec_siigetbyte(slave, a++);
00497         SM->Sreg = ec_siigetbyte(slave, a++);
00498         SM->Activate = ec_siigetbyte(slave, a++);
00499         SM->PDIctrl = ec_siigetbyte(slave, a++);
00500         retVal = 1;
00501     }
00502   if (eectl) ec_eeprom2pdi(slave); /* if eeprom control was previously pdi then restore */
00503     return retVal;
00504 }
00505 
00506 /** Get PDO data from SII PDO section in slave EEPROM.
00507  *  @param[in] slave  = slave number
00508  *  @param[out] PDO   = PDO struct from SII
00509  *  @param[in] t    = 0=RXPDO 1=TXPDO
00510  *  @return mapping size in bits of PDO
00511  */
00512 int ec_siiPDO(uint16 slave, ec_eepromPDOt* PDO, uint8 t)
00513 {
00514     uint16 a , w, c, e, er, Size;
00515   uint8 eectl = ec_slave[slave].eep_pdi;
00516 
00517   Size = 0;
00518     PDO->nPDO = 0;
00519     PDO->Length = 0;
00520     PDO->Index[1] = 0;
00521   for (c = 0 ; c < EC_MAXSM ; c++) PDO->SMbitsize[c] = 0;
00522     if (t > 1)
00523         t = 1;
00524     PDO->Startpos = ec_siifind(slave, ECT_SII_PDO + t);
00525     if (PDO->Startpos > 0)
00526     {
00527     a = PDO->Startpos;
00528     w = ec_siigetbyte(slave, a++);
00529     w += (ec_siigetbyte(slave, a++) << 8);
00530         PDO->Length = w;
00531         c = 1;
00532     /* traverse through all PDOs */
00533         do
00534         {
00535             PDO->nPDO++;
00536             PDO->Index[PDO->nPDO] = ec_siigetbyte(slave, a++);
00537       PDO->Index[PDO->nPDO] += (ec_siigetbyte(slave, a++) << 8);
00538             PDO->BitSize[PDO->nPDO] = 0;
00539             c++;
00540             e = ec_siigetbyte(slave, a++);
00541             PDO->SyncM[PDO->nPDO] = ec_siigetbyte(slave, a++);
00542       a += 4;
00543             c += 2;
00544       if (PDO->SyncM[PDO->nPDO] < EC_MAXSM) /* active and in range SM? */
00545       { 
00546         /* read all entries defined in PDO */
00547               for (er = 1; er <= e; er++)
00548             {
00549                 c += 4;
00550           a += 5;
00551                   PDO->BitSize[PDO->nPDO] += ec_siigetbyte(slave, a++);
00552           a += 2;
00553             }
00554         PDO->SMbitsize[ PDO->SyncM[PDO->nPDO] ] += PDO->BitSize[PDO->nPDO];
00555         Size += PDO->BitSize[PDO->nPDO];
00556             c++;
00557       }
00558       else /* PDO deactivated because SM is 0xff or > EC_MAXSM */
00559       {
00560         c += 4 * e;
00561         a += 8 * e;
00562         c++;
00563       } 
00564       if (PDO->nPDO >= (EC_MAXEEPDO - 1)) c = PDO->Length; /* limit number of PDO entries in buffer */
00565         }
00566         while (c < PDO->Length);
00567     }
00568   if (eectl) ec_eeprom2pdi(slave); /* if eeprom control was previously pdi then restore */
00569 
00570     return (Size);
00571 }
00572 
00573 /** Read all slave states in ec_slave. 
00574  * @return lowest state found
00575  */
00576 int ec_readstate(void)
00577 {
00578     uint16 slave, configadr, lowest, rval;
00579   ec_alstatust slstat;
00580 
00581   lowest = 0xff;
00582   ec_slave[0].ALstatuscode = 0;
00583     for (slave = 1; slave <= ec_slavecount; slave++)
00584     {
00585         configadr = ec_slave[slave].configadr;
00586     slstat.alstatus = 0;
00587     slstat.alstatuscode = 0;
00588         ec_FPRD(configadr, ECT_REG_ALSTAT, sizeof(slstat), &slstat, EC_TIMEOUTRET);
00589     rval = etohs(slstat.alstatus);
00590     ec_slave[slave].ALstatuscode = etohs(slstat.alstatuscode);
00591     if (rval < lowest)
00592       lowest = rval;
00593     ec_slave[slave].state = rval;
00594     ec_slave[0].ALstatuscode |= ec_slave[slave].ALstatuscode;
00595     }
00596   ec_slave[0].state = lowest;
00597 
00598     return lowest;
00599 }
00600 
00601 /** Write slave state, if slave = 0 then write to all slaves.
00602  * The function does not check if the actual state is changed.
00603  * @param[in] slave = Slave number, 0 = master
00604  * @return 0
00605  */
00606 int ec_writestate(uint16 slave)
00607 {
00608     uint16 configadr, slstate;
00609 
00610   if (slave == 0)
00611   {
00612     slstate = htoes(ec_slave[slave].state);
00613     ec_BWR(0, ECT_REG_ALCTL, sizeof(slstate), &slstate, EC_TIMEOUTRET); /* write slave status */
00614   }
00615   else
00616   {
00617     configadr = ec_slave[slave].configadr;
00618     ec_FPWRw(configadr, ECT_REG_ALCTL, htoes(ec_slave[slave].state), EC_TIMEOUTRET); /* write slave status */
00619   }
00620   return 0;
00621 }
00622 
00623 /** Check actual slave state.
00624  * This is a blocking function.
00625  * @param[in] slave   = Slave number, 0 = all slaves
00626  * @param[in] reqstate  = Requested state
00627  * @param[in] timeout = Timout value in us
00628  * @return Requested state, or found state after timeout.
00629  */
00630 uint16 ec_statecheck(uint16 slave, uint16 reqstate, int timeout)
00631 {
00632     uint16 configadr, state, rval;
00633   struct timeval tv1, tv2, tve;
00634   ec_alstatust slstat;
00635   
00636   if ( slave > ec_slavecount ) return 0;
00637   gettimeofday(&tv1, 0);
00638   tv2.tv_sec = 0;
00639   tv2.tv_usec = timeout;
00640   timeradd(&tv1, &tv2, &tve);
00641     configadr = ec_slave[slave].configadr;
00642     do
00643     {
00644     if (slave < 1)
00645     {
00646       rval = 0;
00647           ec_BRD(0, ECT_REG_ALSTAT, sizeof(rval), &rval , EC_TIMEOUTRET);
00648       rval = etohs(rval);
00649     }
00650     else
00651     { 
00652       slstat.alstatus = 0;
00653       slstat.alstatuscode = 0;
00654           ec_FPRD(configadr, ECT_REG_ALSTAT, sizeof(slstat), &slstat, EC_TIMEOUTRET);
00655       rval = etohs(slstat.alstatus);
00656       ec_slave[slave].ALstatuscode = etohs(slstat.alstatuscode);
00657     }
00658     state = rval & 0x000f; /* read slave status */
00659         if (state != reqstate) usleep(1000);
00660     gettimeofday(&tv2, 0);
00661     }
00662   while ((state != reqstate) && timercmp(&tv2, &tve, <));
00663     ec_slave[slave].state = rval;
00664 
00665   return state;
00666 }
00667 
00668 /** Get index of next mailbox counter value.
00669  * Used for Mailbox Link Layer.
00670  * @param[in] cnt   = Mailbox counter value [0..7]
00671  * @return next mailbox counter value
00672  */
00673 uint8 ec_nextmbxcnt(uint8 cnt)
00674 {
00675     cnt++;
00676     if (cnt > 7)
00677         cnt = 1; /* wrap around to 1, not 0 */
00678     return cnt;
00679 }
00680 
00681 /** Clear mailbox buffer.
00682  * @param[out] Mbx    = Mailbox buffer to clear
00683  */
00684 void ec_clearmbx(ec_mbxbuft *Mbx)
00685 {
00686     memset(*Mbx, 0x00, EC_MAXMBX);
00687 }
00688 
00689 /** Check if IN mailbox of slave is empty.
00690  * @param[in] slave   = Slave number
00691  * @param[in] timeout = Timeout in us
00692  * @return >0 is success
00693  */
00694 int ec_mbxempty(uint16 slave, int timeout)
00695 {
00696     uint16 configadr;
00697     uint8 SMstat;
00698   int wkc;
00699   struct timeval tv1, tv2, tve;
00700   
00701   gettimeofday(&tv1, 0);
00702   tv2.tv_sec = 0;
00703   tv2.tv_usec = timeout;
00704   timeradd(&tv1, &tv2, &tve);
00705     configadr = ec_slave[slave].configadr;
00706     do
00707     {     
00708         wkc = ec_FPRD(configadr, ECT_REG_SM0STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET);
00709       SMstat = etohs(SMstat);
00710       if (((SMstat & 0x08) != 0) && (timeout > EC_LOCALDELAY)) usleep(EC_LOCALDELAY);
00711       gettimeofday(&tv2, 0);
00712     } 
00713     while (((wkc <= 0) || ((SMstat & 0x08) != 0)) && timercmp(&tv2, &tve, <));
00714   if ((wkc > 0) && ((SMstat & 0x08) == 0)) return 1;
00715   return 0;
00716 }
00717   
00718 /** Write IN mailbox to slave.
00719  * @param[in] slave   = Slave number
00720  * @param[out] mbx      = Mailbox data
00721  * @param[in] timeout = Timeout in us
00722  * @return Work counter (>0 is success)
00723  */
00724 int ec_mbxsend(uint16 slave,ec_mbxbuft *mbx, int timeout)
00725 {
00726   uint16 mbxwo,mbxl,configadr;
00727   int wkc;
00728 
00729   wkc = 0;
00730   configadr = ec_slave[slave].configadr;
00731   mbxl = ec_slave[slave].mbx_l;
00732   if (mbxl > 0)
00733   {
00734     if (ec_mbxempty(slave, timeout))
00735     {
00736       mbxwo = ec_slave[slave].mbx_wo;
00737       /* write slave in mailbox */
00738       wkc = ec_FPWR(configadr, mbxwo, mbxl, mbx, EC_TIMEOUTRET);  
00739     }
00740     else 
00741       wkc = 0;
00742   }
00743 
00744   return wkc;
00745 }
00746 
00747 /** Read OUT mailbox from slave.
00748  * Supports Mailbox Link Layer with repeat requests.
00749  * @param[in] slave   = Slave number
00750  * @param[out] mbx      = Mailbox data
00751  * @param[in] timeout = Timeout in us
00752  * @return Work counter (>0 is success)
00753  */
00754 int ec_mbxreceive(uint16 slave, ec_mbxbuft *mbx, int timeout)
00755 {
00756     uint16 mbxro,mbxl,configadr;
00757   int wkc=0;
00758   int wkc2;
00759     uint16 SMstat;
00760   uint8 SMcontr;
00761   ec_mbxheadert *mbxh;
00762     ec_emcyt *EMp;
00763   struct timeval mtv1, mtv2, mtve;
00764   
00765   configadr = ec_slave[slave].configadr;
00766   mbxl = ec_slave[slave].mbx_rl;
00767     if (mbxl > 0)
00768     {
00769     gettimeofday(&mtv1, 0);
00770     mtv2.tv_sec = 0;
00771     mtv2.tv_usec = timeout;
00772     timeradd(&mtv1, &mtv2, &mtve);
00773       wkc = 0;
00774       do /* wait for read mailbox available */
00775     {
00776         wkc = ec_FPRD(configadr, ECT_REG_SM1STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET);
00777       SMstat = etohs(SMstat);
00778       if (((SMstat & 0x08) == 0) && (timeout > EC_LOCALDELAY))
00779         usleep(EC_LOCALDELAY);
00780       gettimeofday(&mtv2, 0);
00781       }
00782     while (((wkc <= 0) || ((SMstat & 0x08) == 0)) && timercmp(&mtv2, &mtve, <));
00783 
00784       if ((wkc > 0) && ((SMstat & 0x08) > 0)) /* read mailbox available ? */
00785       {
00786         mbxro = ec_slave[slave].mbx_ro;
00787       mbxh = (ec_mbxheadert *)mbx;
00788       do
00789       { 
00790               wkc = ec_FPRD(configadr, mbxro, mbxl, mbx, EC_TIMEOUTRET); /* get mailbox */
00791 /* TODO : check for mailbox error response */       
00792             if ((wkc > 0) && ((mbxh->mbxtype & 0x0f) == 0x03)) /* CoE response? */
00793             {
00794           EMp = (ec_emcyt *)mbx;
00795                   if ((etohs(EMp->CANOpen) >> 12) == 0x01) /* Emergency request? */
00796                 {
00797                     ec_mbxemergencyerror(slave, etohs(EMp->ErrorCode), EMp->ErrorReg, 
00798                         EMp->bData, etohs(EMp->w1), etohs(EMp->w2));
00799             wkc = 0; /* prevent emergency to cascade up, it is already handled. */
00800                   }
00801             }
00802         else
00803         {  
00804           if (wkc <= 0) /* read mailbox lost */
00805           {
00806             SMstat ^= 0x0200; /* toggle repeat request */
00807             SMstat = htoes(SMstat);
00808             wkc2 = ec_FPWR(configadr, ECT_REG_SM1STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET);
00809             SMstat = etohs(SMstat);
00810               do /* wait for toggle ack */
00811             {
00812                 wkc2 = ec_FPRD(configadr, ECT_REG_SM1CONTR, sizeof(SMcontr), &SMcontr, EC_TIMEOUTRET);
00813               gettimeofday(&mtv2, 0);
00814               } while (((wkc2 <= 0) || ((SMcontr & 0x02) != (HI_BYTE(SMstat) & 0x02))) && timercmp(&mtv2, &mtve, <));
00815               do /* wait for read mailbox available */
00816             {
00817                 wkc2 = ec_FPRD(configadr, ECT_REG_SM1STAT, sizeof(SMstat), &SMstat, EC_TIMEOUTRET);
00818               SMstat = etohs(SMstat);
00819               if (((SMstat & 0x08) == 0) && (timeout > EC_LOCALDELAY)) 
00820               {
00821                 usleep(EC_LOCALDELAY);
00822               }
00823               gettimeofday(&mtv2, 0);
00824               } while (((wkc2 <= 0) || ((SMstat & 0x08) == 0)) && timercmp(&mtv2, &mtve, <));
00825           } 
00826         }
00827       } while ((wkc <= 0) && timercmp(&mtv2, &mtve, <)); /* if WKC<=0 repeat */
00828       }
00829     else /* no read mailbox available */
00830         wkc = 0;
00831   }
00832   
00833     return wkc;
00834 }
00835 
00836 /** Dump complete EEPROM data from slave in buffer.
00837  * @param[in] slave   = Slave number
00838  * @param[out] esibuf   = EEPROM data buffer, make sure it is big enough.
00839  */
00840 void ec_esidump(uint16 slave, uint8 *esibuf, uint8 test)
00841 {
00842   int address, incr;
00843   uint16 configadr;
00844   uint64 *p64;
00845   uint16 *p16;
00846   uint64 edat;
00847   uint8 eectl = ec_slave[slave].eep_pdi;
00848 
00849   ec_eeprom2master(slave); /* set eeprom control to master */
00850     configadr = ec_slave[slave].configadr;
00851   address = ECT_SII_START;
00852   p16=(uint16*)esibuf;
00853   if (ec_slave[slave].eep_8byte) 
00854     incr = 4; 
00855   else 
00856     incr = 2;
00857   do
00858   {
00859     edat = ec_readeepromFP(configadr, address, EC_TIMEOUTEEP);
00860     p64 = (uint64*)p16;
00861     *p64 = edat;
00862     p16 += incr;
00863     address += incr; 
00864   } while ((address <= (EC_MAXEEPBUF >> 1)) && ((uint32)edat != 0xffffffff));
00865 
00866   if (eectl) ec_eeprom2pdi(slave); /* if eeprom control was previously pdi then restore */
00867 }
00868 
00869 /** Read EEPROM from slave bypassing cache.
00870  * @param[in] slave   = Slave number
00871  * @param[in] eeproma   = (WORD) Address in the EEPROM
00872  * @param[in] timeout = Timeout in us.
00873  * @return EEPROM data 32bit
00874  */
00875 uint32 ec_readeeprom(uint16 slave, uint16 eeproma, int timeout)
00876 {
00877     uint16 configadr;
00878 
00879   ec_eeprom2master(slave); /* set eeprom control to master */
00880     configadr = ec_slave[slave].configadr;
00881     return (ec_readeepromFP(configadr, eeproma, timeout));
00882 }
00883 
00884 /** Write EEPROM to slave bypassing cache.
00885  * @param[in] slave   = Slave number
00886  * @param[in] eeproma   = (WORD) Address in the EEPROM
00887  * @param[in] data    = 16bit data
00888  * @param[in] timeout = Timeout in us.
00889  * @return >0 if OK
00890  */
00891 int ec_writeeeprom(uint16 slave, uint16 eeproma, uint16 data, int timeout)
00892 {
00893     uint16 configadr;
00894 
00895   ec_eeprom2master(slave); /* set eeprom control to master */
00896     configadr = ec_slave[slave].configadr;
00897     return (ec_writeeepromFP(configadr, eeproma, data, timeout));
00898 }
00899 
00900 
00901 /** Set eeprom control to master. Only if set to PDI.
00902  * @param[in] slave   = Slave number
00903  * @return >0 if OK
00904  */
00905 int ec_eeprom2master(uint16 slave)
00906 {
00907   int wkc = 1, cnt = 0;
00908     uint16 configadr;
00909   uint8 eepctl;
00910 
00911   if ( ec_slave[slave].eep_pdi )
00912   {
00913       configadr = ec_slave[slave].configadr; 
00914     eepctl = 2;
00915     do
00916     {
00917       wkc = ec_FPWR(configadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* force Eeprom from PDI */
00918     }
00919     while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
00920     eepctl = 0;
00921     cnt = 0;
00922     do
00923     {
00924       wkc = ec_FPWR(configadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to master */
00925     }
00926     while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
00927     ec_slave[slave].eep_pdi = 0;
00928   }
00929 
00930   return wkc;
00931 } 
00932 
00933 /** Set eeprom control to PDI. Only if set to master.
00934  * @param[in] slave   = Slave number
00935  * @return >0 if OK
00936  */
00937 int ec_eeprom2pdi(uint16 slave)
00938 {
00939   int wkc = 1, cnt = 0;
00940     uint16 configadr;
00941   uint8 eepctl;
00942 
00943   if ( !ec_slave[slave].eep_pdi )
00944   {
00945       configadr = ec_slave[slave].configadr; 
00946     eepctl = 1;
00947     do
00948     {
00949       wkc = ec_FPWR(configadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to PDI */
00950     }
00951     while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
00952     ec_slave[slave].eep_pdi = 1;
00953   }
00954 
00955   return wkc;
00956 } 
00957 
00958 uint16 ec_eeprom_waitnotbusyAP(uint16 aiadr,uint16 *estat, int timeout)
00959 {
00960   int wkc, cnt = 0, retval = 0;
00961   struct timeval tv1, tv2, tve;
00962   
00963   gettimeofday(&tv1, 0);
00964   tv2.tv_sec = 0;
00965   tv2.tv_usec = timeout;
00966   timeradd(&tv1, &tv2, &tve);
00967   do
00968   {
00969     if (cnt++) usleep(EC_LOCALDELAY);
00970     wkc=ec_APRD(aiadr, ECT_REG_EEPSTAT, sizeof(*estat), estat, EC_TIMEOUTRET);
00971     *estat = etohs(*estat);
00972     gettimeofday(&tv2, 0);
00973   }
00974   while (((wkc <= 0) || ((*estat & EC_ESTAT_BUSY) > 0)) && (timercmp(&tv2, &tve, <))); /* wait for eeprom ready */
00975   if ((*estat & EC_ESTAT_BUSY) == 0) retval = 1;
00976   return retval;
00977 }
00978 
00979 /** Read EEPROM from slave bypassing cache. APRD method.
00980  * @param[in] aiadr   = auto increment address of slave
00981  * @param[in] eeproma   = (WORD) Address in the EEPROM
00982  * @param[in] timeout = Timeout in us.
00983  * @return EEPROM data 64bit or 32bit
00984  */
00985 uint64 ec_readeepromAP(uint16 aiadr, uint16 eeproma, int timeout)
00986 {
00987     uint16 estat;
00988     uint32 edat32;
00989   uint64 edat64;
00990     ec_eepromt ed;
00991   int wkc, cnt, nackcnt = 0;
00992   struct timeval tv1, tv2, tve;
00993   
00994   gettimeofday(&tv1, 0);
00995   tv2.tv_sec = 0;
00996   tv2.tv_usec = timeout;
00997   timeradd(&tv1, &tv2, &tve);
00998   edat64 = 0;
00999   edat32 = 0;
01000   if (ec_eeprom_waitnotbusyAP(aiadr, &estat, timeout))
01001   {
01002     if (estat & EC_ESTAT_EMASK) /* error bits are set */
01003     {
01004       estat = htoes(EC_ECMD_NOP); /* clear error bits */
01005       wkc=ec_APWR(aiadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET);
01006     }
01007 
01008     do
01009     {
01010       ed.comm = htoes(EC_ECMD_READ);
01011       ed.addr = htoes(eeproma);
01012       ed.d2   = 0x0000;
01013       cnt = 0;
01014       do
01015         wkc=ec_APWR(aiadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET);
01016       while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
01017       if (wkc)
01018       {
01019         usleep(EC_LOCALDELAY);
01020         estat = 0x0000;
01021         if (ec_eeprom_waitnotbusyAP(aiadr, &estat, timeout))
01022         { 
01023           if (estat & EC_ESTAT_NACK)
01024           {
01025             nackcnt++;
01026             usleep(EC_LOCALDELAY * 5);
01027           }
01028           else
01029           {
01030             nackcnt = 0;
01031             if (estat & EC_ESTAT_R64)
01032             {
01033               cnt = 0;
01034               do
01035                 wkc=ec_APRD(aiadr, ECT_REG_EEPDAT, sizeof(edat64), &edat64, EC_TIMEOUTRET);
01036               while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
01037             }
01038             else
01039             { 
01040               cnt = 0;
01041               do
01042                 wkc=ec_APRD(aiadr, ECT_REG_EEPDAT, sizeof(edat32), &edat32, EC_TIMEOUTRET);
01043               while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
01044               edat64=(uint64)edat32;
01045             }
01046           }
01047         } 
01048       }     
01049     }
01050     while ((nackcnt > 0) && (nackcnt < 3));
01051   }
01052     return edat64;
01053 }
01054 
01055 /** Write EEPROM to slave bypassing cache. APWR method.
01056  * @param[in] aiadr   = configured address of slave
01057  * @param[in] eeproma   = (WORD) Address in the EEPROM
01058  * @param[in] data    = 16bit data
01059  * @param[in] timeout = Timeout in us.
01060  * @return >0 if OK
01061  */
01062 int ec_writeeepromAP(uint16 aiadr, uint16 eeproma, uint16 data, int timeout)
01063 {
01064     uint16 estat;
01065     ec_eepromt ed;
01066   int wkc, rval = 0, cnt = 0, nackcnt = 0;
01067   struct timeval tv1, tv2, tve;
01068 
01069   gettimeofday(&tv1, 0);
01070   tv2.tv_sec = 0;
01071   tv2.tv_usec = timeout;
01072   timeradd(&tv1, &tv2, &tve);
01073   if (ec_eeprom_waitnotbusyAP(aiadr, &estat, timeout))
01074   {
01075     if (estat & EC_ESTAT_EMASK) /* error bits are set */
01076     {
01077       estat = htoes(EC_ECMD_NOP); /* clear error bits */
01078       wkc=ec_APWR(aiadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET);
01079     }
01080     do
01081     {
01082       cnt = 0;
01083       do
01084         wkc=ec_APWR(aiadr, ECT_REG_EEPDAT, sizeof(data), &data, EC_TIMEOUTRET);
01085       while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
01086 
01087       ed.comm = EC_ECMD_WRITE;
01088       ed.addr = eeproma;
01089       ed.d2   = 0x0000;
01090       cnt = 0;
01091       do
01092         wkc=ec_APWR(aiadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET);
01093       while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
01094       if (wkc)
01095       {
01096         usleep(EC_LOCALDELAY * 2);
01097         estat = 0x0000;
01098         if (ec_eeprom_waitnotbusyAP(aiadr, &estat, timeout))
01099         { 
01100           if (estat & EC_ESTAT_NACK)
01101           {
01102             nackcnt++;
01103             usleep(EC_LOCALDELAY * 5);
01104           }
01105           else
01106           {
01107             nackcnt = 0;
01108             rval = 1;
01109           }
01110         }
01111       }
01112 
01113     }
01114     while ((nackcnt > 0) && (nackcnt < 3));   
01115   }
01116     return rval;
01117 }
01118 
01119 uint16 ec_eeprom_waitnotbusyFP(uint16 configadr,uint16 *estat, int timeout)
01120 {
01121   int wkc, cnt = 0, retval = 0;
01122   struct timeval tv1, tv2, tve;
01123   
01124   gettimeofday(&tv1, 0);
01125   tv2.tv_sec = 0;
01126   tv2.tv_usec = timeout;
01127   timeradd(&tv1, &tv2, &tve);
01128   do
01129   {
01130     if (cnt++) usleep(EC_LOCALDELAY);
01131     wkc=ec_FPRD(configadr, ECT_REG_EEPSTAT, sizeof(*estat), estat, EC_TIMEOUTRET);
01132     *estat = etohs(*estat);
01133     gettimeofday(&tv2, 0);
01134   }
01135   while (((wkc <= 0) || ((*estat & EC_ESTAT_BUSY) > 0)) && (timercmp(&tv2, &tve, <))); /* wait for eeprom ready */
01136   if ((*estat & EC_ESTAT_BUSY) == 0) retval = 1;
01137   return retval;
01138 }
01139 
01140 /** Read EEPROM from slave bypassing cache. FPRD method.
01141  * @param[in] configadr = configured address of slave
01142  * @param[in] eeproma   = (WORD) Address in the EEPROM
01143  * @param[in] timeout = Timeout in us.
01144  * @return EEPROM data 64bit or 32bit
01145  */
01146 uint64 ec_readeepromFP(uint16 configadr, uint16 eeproma, int timeout)
01147 {
01148     uint16 estat;
01149     uint32 edat32;
01150   uint64 edat64;
01151     ec_eepromt ed;
01152   int wkc, cnt, nackcnt = 0;
01153   struct timeval tv1, tv2, tve;
01154   
01155   gettimeofday(&tv1, 0);
01156   tv2.tv_sec = 0;
01157   tv2.tv_usec = timeout;
01158   timeradd(&tv1, &tv2, &tve);
01159   edat64 = 0;
01160   edat32 = 0;
01161   if (ec_eeprom_waitnotbusyFP(configadr, &estat, timeout))
01162   {
01163     if (estat & EC_ESTAT_EMASK) /* error bits are set */
01164     {
01165       estat = htoes(EC_ECMD_NOP); /* clear error bits */
01166       wkc=ec_FPWR(configadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET);
01167     }
01168 
01169     do
01170     {
01171       ed.comm = htoes(EC_ECMD_READ);
01172       ed.addr = htoes(eeproma);
01173       ed.d2   = 0x0000;
01174       cnt = 0;
01175       do
01176         wkc=ec_FPWR(configadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET);
01177       while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
01178       if (wkc)
01179       {
01180         usleep(EC_LOCALDELAY);
01181         estat = 0x0000;
01182         if (ec_eeprom_waitnotbusyFP(configadr, &estat, timeout))
01183         { 
01184           if (estat & EC_ESTAT_NACK)
01185           {
01186             nackcnt++;
01187             usleep(EC_LOCALDELAY * 5);
01188           }
01189           else
01190           {
01191             nackcnt = 0;
01192             if (estat & EC_ESTAT_R64)
01193             {
01194               cnt = 0;
01195               do
01196                 wkc=ec_FPRD(configadr, ECT_REG_EEPDAT, sizeof(edat64), &edat64, EC_TIMEOUTRET);
01197               while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
01198             }
01199             else
01200             { 
01201               cnt = 0;
01202               do
01203                 wkc=ec_FPRD(configadr, ECT_REG_EEPDAT, sizeof(edat32), &edat32, EC_TIMEOUTRET);
01204               while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
01205               edat64=(uint64)edat32;
01206             }
01207           }
01208         } 
01209       }     
01210     }
01211     while ((nackcnt > 0) && (nackcnt < 3));
01212   }
01213     return edat64;
01214 }
01215 
01216 /** Write EEPROM to slave bypassing cache. FPWR method.
01217  * @param[in] configadr = configured address of slave
01218  * @param[in] eeproma   = (WORD) Address in the EEPROM
01219  * @param[in] data    = 16bit data
01220  * @param[in] timeout = Timeout in us.
01221  * @return >0 if OK
01222  */
01223 int ec_writeeepromFP(uint16 configadr, uint16 eeproma, uint16 data, int timeout)
01224 {
01225     uint16 estat;
01226     ec_eepromt ed;
01227   int wkc, rval = 0, cnt = 0, nackcnt = 0;
01228   struct timeval tv1, tv2, tve;
01229   
01230   gettimeofday(&tv1, 0);
01231   tv2.tv_sec = 0;
01232   tv2.tv_usec = timeout;
01233   timeradd(&tv1, &tv2, &tve);
01234   if (ec_eeprom_waitnotbusyFP(configadr, &estat, timeout))
01235   {
01236     if (estat & EC_ESTAT_EMASK) /* error bits are set */
01237     {
01238       estat = htoes(EC_ECMD_NOP); /* clear error bits */
01239       wkc=ec_FPWR(configadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET);
01240     }
01241     do
01242     {
01243       cnt = 0;
01244       do
01245         wkc=ec_FPWR(configadr, ECT_REG_EEPDAT, sizeof(data), &data, EC_TIMEOUTRET);
01246       while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
01247       ed.comm = EC_ECMD_WRITE;
01248       ed.addr = eeproma;
01249       ed.d2   = 0x0000;
01250       cnt = 0;
01251       do
01252         wkc=ec_FPWR(configadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET);
01253       while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
01254       if (wkc)
01255       {
01256         usleep(EC_LOCALDELAY * 2);
01257         estat = 0x0000;
01258         if (ec_eeprom_waitnotbusyFP(configadr, &estat, timeout))
01259         { 
01260           if (estat & EC_ESTAT_NACK)
01261           {
01262             nackcnt++;
01263             usleep(EC_LOCALDELAY * 5);
01264           }
01265           else
01266           {
01267             nackcnt = 0;
01268             rval = 1;
01269           }
01270         }
01271       }
01272     }
01273     while ((nackcnt > 0) && (nackcnt < 3));   
01274   }
01275     return rval;
01276 }
01277 
01278 /** Read EEPROM from slave bypassing cache.
01279  * Parallel read step 1, make request to slave.
01280  * @param[in] slave   = Slave number
01281  * @param[in] eeproma   = (WORD) Address in the EEPROM
01282  */
01283 void ec_readeeprom1(uint16 slave, uint16 eeproma)
01284 {
01285     uint16 configadr, estat;
01286     ec_eepromt ed;
01287   int wkc, cnt = 0;
01288 
01289   ec_eeprom2master(slave); /* set eeprom control to master */
01290     configadr = ec_slave[slave].configadr;
01291   if (ec_eeprom_waitnotbusyFP(configadr, &estat, EC_TIMEOUTEEP))
01292   {
01293     if (estat & EC_ESTAT_EMASK) /* error bits are set */
01294     {
01295       estat = htoes(EC_ECMD_NOP); /* clear error bits */
01296       wkc=ec_FPWR(configadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET);
01297     }
01298     ed.comm = htoes(EC_ECMD_READ);
01299     ed.addr = htoes(eeproma);
01300     ed.d2   = 0x0000;
01301     do
01302       wkc = ec_FPWR(configadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET);
01303     while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
01304   }
01305 }
01306 
01307 /** Read EEPROM from slave bypassing cache.
01308  * Parallel read step 2, actual read from slave.
01309  * @param[in] slave   = Slave number
01310  * @param[in] timeout = Timeout in us.
01311  * @return EEPROM data 32bit
01312  */
01313 uint32 ec_readeeprom2(uint16 slave, int timeout)
01314 {
01315     uint16 estat, configadr;
01316     uint32 edat;
01317   int wkc, cnt = 0;
01318   struct timeval tv1, tv2, tve;
01319   
01320   gettimeofday(&tv1, 0);
01321   tv2.tv_sec = 0;
01322   tv2.tv_usec = timeout;
01323   timeradd(&tv1, &tv2, &tve);
01324     configadr = ec_slave[slave].configadr;
01325   edat = 0;
01326     estat = 0x0000;
01327   if (ec_eeprom_waitnotbusyFP(configadr, &estat, timeout))
01328   { 
01329     do
01330         wkc = ec_FPRD(configadr, ECT_REG_EEPDAT, sizeof(edat), &edat, EC_TIMEOUTRET);
01331     while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
01332   }
01333 
01334     return edat;
01335 }
01336 
01337 /** Push index of segmented LRD/LWR/LRW combination.
01338  * @param[in] idx     = Used datagram index.
01339  * @param[in] data      = Pointer to process data segment.
01340  * @param[in] length    = Length of data segment in bytes.
01341  */
01342 static void ec_pushindex(uint8 idx, void *data, uint16 length)
01343 {
01344   if(ec_idxstack.pushed < EC_MAXBUF)
01345   {
01346     ec_idxstack.idx[ec_idxstack.pushed] = idx;
01347     ec_idxstack.data[ec_idxstack.pushed] = data;
01348     ec_idxstack.length[ec_idxstack.pushed] = length;
01349     ec_idxstack.pushed++;
01350   } 
01351 } 
01352 
01353 /** Pull index of segmented LRD/LWR/LRW combination.
01354  * @return Stack location, -1 if stack is empty.
01355  */
01356 static int ec_pullindex(void)
01357 {
01358   int rval = -1;
01359   if(ec_idxstack.pulled < ec_idxstack.pushed)
01360   {
01361     rval = ec_idxstack.pulled;
01362     ec_idxstack.pulled++;
01363   }
01364   
01365   return rval;
01366 } 
01367 
01368 /** Transmit processdata to slaves.
01369  * Uses LRW, or LRD/LWR if LRW is not allowed (blockLRW).
01370  * Both the input and output processdata are transmitted.
01371  * The outputs with the actual data, the inputs have a placeholder.
01372  * The inputs are gathered with the receive processdata function.
01373  * In contrast to the base LRW function this function is non-blocking.
01374  * If the processdata does not fit in one datagram, multiple are used.
01375  * In order to recombine the slave response, a stack is used.
01376  * @return >0 if processdata is transmitted.
01377  */
01378 int ec_send_processdata_group(uint8 group)
01379 {
01380   uint32 LogAdr;
01381   uint16 w1, w2;
01382   int length, sublength;
01383     uint8 idx;
01384   int wkc;
01385   void* data;
01386   boolean first=FALSE;
01387   uint16 currentsegment = 0;
01388 
01389   wkc = 0;
01390   if(ec_group[group].hasdc)
01391     first = TRUE;
01392   length = ec_group[group].Obytes + ec_group[group].Ibytes;
01393   LogAdr = ec_group[group].logstartaddr;
01394   if (length)
01395   { 
01396     if(!group)
01397     {
01398       ec_idxstack.pushed = 0;
01399       ec_idxstack.pulled = 0;
01400     }
01401     wkc = 1;
01402     /* LRW blocked by one or more slaves ? */
01403     if (ec_group[group].blockLRW)
01404     {
01405       /* if inputs available generate LRD */
01406       if(ec_group[group].Ibytes)
01407       {
01408         currentsegment = ec_group[group].Isegment;
01409         data=ec_group[group].inputs;
01410         length = ec_group[group].Ibytes;
01411         LogAdr += ec_group[group].Obytes;
01412         /* segment transfer if needed */
01413         do
01414         {     
01415           if(currentsegment == ec_group[group].Isegment)
01416             sublength = ec_group[group].IOsegment[currentsegment++] - ec_group[group].Ioffset;
01417           else
01418             sublength = ec_group[group].IOsegment[currentsegment++];
01419           /* get new index */
01420             idx = ec_getindex();
01421           w1 = LO_WORD(LogAdr);
01422           w2 = HI_WORD(LogAdr);
01423             ec_setupdatagram(&ec_txbuf[idx], EC_CMD_LRD, idx, w1, w2, sublength, data);
01424           /* send frame */
01425           ec_outframe_red(idx);
01426           /* push index and data pointer on stack */
01427           ec_pushindex(idx, data, sublength);
01428           length -= sublength;
01429           LogAdr += sublength;
01430           data += sublength;
01431         } while (length && (currentsegment < ec_group[group].nsegments)); 
01432       } 
01433       /* if outputs available generate LWR */
01434       if(ec_group[group].Obytes)
01435       {
01436         data=ec_group[group].outputs;
01437         length = ec_group[group].Obytes;
01438         LogAdr = ec_group[group].logstartaddr;
01439         currentsegment = 0;
01440         /* segment transfer if needed */
01441         do
01442         {     
01443           sublength = ec_group[group].IOsegment[currentsegment++];
01444           if((length - sublength) < 0)
01445             sublength = length;
01446           /* get new index */
01447             idx = ec_getindex();
01448           w1 = LO_WORD(LogAdr);
01449           w2 = HI_WORD(LogAdr);
01450             ec_setupdatagram(&ec_txbuf[idx], EC_CMD_LWR, idx, w1, w2, sublength, data);
01451           /* send frame */
01452           ec_outframe_red(idx);
01453           /* push index and data pointer on stack */
01454           ec_pushindex(idx, data, sublength);
01455           length -= sublength;
01456           LogAdr += sublength;
01457           data += sublength;
01458         } while (length && (currentsegment < ec_group[group].nsegments)); 
01459       }
01460     }
01461     /* LRW can be used */
01462     else
01463     { 
01464       if (ec_group[group].Obytes)
01465         data=ec_group[group].outputs;
01466       else
01467         data=ec_group[group].inputs;
01468       /* segment transfer if needed */
01469       do
01470       {     
01471         sublength = ec_group[group].IOsegment[currentsegment++];
01472         /* get new index */
01473           idx = ec_getindex();
01474           w1 = LO_WORD(LogAdr);
01475         w2 = HI_WORD(LogAdr);
01476           ec_setupdatagram(&ec_txbuf[idx], EC_CMD_LRW, idx, w1, w2, sublength, data);
01477         if(first)
01478         {
01479           ec_DCl = sublength;
01480           /* FPRMW in second datagram */
01481             ec_DCtO = ec_adddatagram(&ec_txbuf[idx], EC_CMD_FRMW, idx, FALSE, 
01482                        ec_slave[ec_group[group].DCnext].configadr, 
01483                        ECT_REG_DCSYSTIME, sizeof(ec_DCtime), &ec_DCtime);
01484           first = FALSE;
01485         }         
01486         /* send frame */
01487         ec_outframe_red(idx);
01488         /* push index and data pointer on stack */
01489         ec_pushindex(idx, data, sublength);
01490         length -= sublength;
01491         LogAdr += sublength;
01492         data += sublength;
01493       } while (length && (currentsegment < ec_group[group].nsegments)); 
01494     } 
01495   } 
01496 
01497   return wkc;
01498 }
01499 
01500 /** Receive processdata from slaves.
01501  * Second part from ec_send_processdata().
01502  * Received datagrams are recombined with the processdata with help from the stack.
01503  * If a datagram contains input processdata it copies it to the processdata structure.
01504  * @param[in] timeout   = Timeout in us.
01505  * @return Work counter.
01506  */
01507 int ec_receive_processdata_group(uint8 group, int timeout)
01508 {
01509     int pos, idx;
01510   int wkc = 0, wkc2;
01511   boolean first = FALSE;
01512 
01513   if(ec_group[group].hasdc)
01514     first = TRUE;
01515   /* get first index */
01516   pos = ec_pullindex();
01517   /* read the same number of frames as send */
01518   while (pos >= 0)
01519   { 
01520     idx = ec_idxstack.idx[pos];
01521       wkc2 = ec_waitinframe(ec_idxstack.idx[pos], timeout);
01522     /* check if there is input data in frame */
01523     if ((wkc2 > EC_NOFRAME) && ((ec_rxbuf[idx][EC_CMDOFFSET]==EC_CMD_LRD) || (ec_rxbuf[idx][EC_CMDOFFSET]==EC_CMD_LRW)))
01524       {
01525       if(first)
01526       { 
01527             memcpy(ec_idxstack.data[pos], &ec_rxbuf[idx][EC_HEADERSIZE], ec_DCl);
01528         memcpy(&wkc, &ec_rxbuf[idx][EC_HEADERSIZE + ec_DCl], EC_WKCSIZE);
01529         wkc = etohs(wkc);
01530         memcpy(&ec_DCtime, &ec_rxbuf[idx][ec_DCtO], sizeof(ec_DCtime));
01531         ec_DCtime = etohll(ec_DCtime);
01532         first = FALSE;
01533       }
01534       else
01535       { 
01536         /* copy input data back to process data buffer */
01537           memcpy(ec_idxstack.data[pos], &ec_rxbuf[idx][EC_HEADERSIZE], ec_idxstack.length[pos]);
01538         wkc += wkc2;
01539       } 
01540       }
01541     /* release buffer */
01542       ec_setbufstat(idx, EC_BUF_EMPTY);
01543     /* get next index */
01544     pos = ec_pullindex();
01545   } 
01546 
01547   return wkc;
01548 } 
01549 
01550 int ec_send_processdata(void)
01551 {
01552   return ec_send_processdata_group(0);
01553 }
01554 
01555 int ec_receive_processdata(int timeout)
01556 {
01557   return ec_receive_processdata_group(0, timeout);
01558 }
Generated by  doxygen 1.6.3