AB&T / SOEM

Dependents:   EasyCAT_LAB_simple EasyCAT_LAB_very_simple EasyCAT_LAB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ethercatconfig.c Source File

ethercatconfig.c

Go to the documentation of this file.
00001 /*
00002  * Licensed under the GNU General Public License version 2 with exceptions. See
00003  * LICENSE file in the project root for full license information
00004  */
00005 
00006 /** \file
00007  * \brief
00008  * Configuration module for EtherCAT master.
00009  *
00010  * After successful initialisation with ec_init() or ec_init_redundant()
00011  * the slaves can be auto configured with this module.
00012  */
00013 
00014 #include <stdio.h>
00015 #include <string.h>
00016 #include "osal.h"
00017 #include "oshw.h"
00018 #include "ethercattype.h"
00019 #include "ethercatbase.h"
00020 #include "ethercatmain.h"
00021 #include "ethercatcoe.h"
00022 #include "ethercatsoe.h"
00023 #include "ethercatconfig.h"
00024 
00025 
00026 typedef struct
00027 {
00028    int thread_n;
00029    int running;
00030    ecx_contextt *context;
00031    uint16 slave;
00032 } ecx_mapt_t;
00033 
00034 ecx_mapt_t ecx_mapt[EC_MAX_MAPT];
00035 #if EC_MAX_MAPT > 1
00036 OSAL_THREAD_HANDLE ecx_threadh[EC_MAX_MAPT];
00037 #endif
00038 
00039 #ifdef EC_VER1
00040 /** Slave configuration structure */
00041 typedef const struct
00042 {
00043    /** Manufacturer code of slave */
00044    uint32           man;
00045    /** ID of slave */
00046    uint32           id;
00047    /** Readable name */
00048    char             name[EC_MAXNAME + 1];
00049    /** Data type */
00050    uint8            Dtype;
00051    /** Input bits */
00052    uint16            Ibits;
00053    /** Output bits */
00054    uint16           Obits;
00055    /** SyncManager 2 address */
00056    uint16           SM2a;
00057    /** SyncManager 2 flags */
00058    uint32           SM2f;
00059    /** SyncManager 3 address */
00060    uint16           SM3a;
00061    /** SyncManager 3 flags */
00062    uint32           SM3f;
00063    /** FMMU 0 activation */
00064    uint8            FM0ac;
00065    /** FMMU 1 activation */
00066    uint8            FM1ac;
00067 } ec_configlist_t;
00068 
00069 #include "ethercatconfiglist.h"
00070 #endif
00071 
00072 /** standard SM0 flags configuration for mailbox slaves */
00073 #define EC_DEFAULTMBXSM0  0x00010026
00074 /** standard SM1 flags configuration for mailbox slaves */
00075 #define EC_DEFAULTMBXSM1  0x00010022
00076 /** standard SM0 flags configuration for digital output slaves */
00077 #define EC_DEFAULTDOSM0   0x00010044
00078 
00079 #ifdef EC_VER1
00080 /** Find slave in standard configuration list ec_configlist[]
00081  *
00082  * @param[in] man      = manufacturer
00083  * @param[in] id       = ID
00084  * @return index in ec_configlist[] when found, otherwise 0
00085  */
00086 int ec_findconfig( uint32 man, uint32 id)
00087 {
00088    int i = 0;
00089 
00090    do
00091    {
00092       i++;
00093    } while ( (ec_configlist[i].man != EC_CONFIGEND) &&
00094            ((ec_configlist[i].man != man) || (ec_configlist[i].id != id)) );
00095    if (ec_configlist[i].man == EC_CONFIGEND)
00096    {
00097       i = 0;
00098    }
00099    return i;
00100 }
00101 #endif
00102 
00103 void ecx_init_context(ecx_contextt *context)
00104 {
00105    int lp;
00106    *(context->slavecount) = 0;
00107    /* clean ec_slave array */
00108    memset(context->slavelist, 0x00, sizeof(ec_slavet) * context->maxslave);
00109    memset(context->grouplist, 0x00, sizeof(ec_groupt) * context->maxgroup);
00110    /* clear slave eeprom cache, does not actually read any eeprom */
00111    ecx_siigetbyte(context, 0, EC_MAXEEPBUF);
00112    for(lp = 0; lp < context->maxgroup; lp++)
00113    {
00114       /* default start address per group entry */
00115       context->grouplist[lp].logstartaddr = lp << EC_LOGGROUPOFFSET;
00116    }
00117 }
00118 
00119 int ecx_detect_slaves(ecx_contextt *context)
00120 {
00121    uint8  b;
00122    uint16 w;
00123    int    wkc;
00124 
00125    /* make special pre-init register writes to enable MAC[1] local administered bit *
00126     * setting for old netX100 slaves */
00127    b = 0x00;
00128    ecx_BWR(context->port, 0x0000, ECT_REG_DLALIAS, sizeof(b), &b, EC_TIMEOUTRET3);     /* Ignore Alias register */
00129    b = EC_STATE_INIT | EC_STATE_ACK;
00130    ecx_BWR(context->port, 0x0000, ECT_REG_ALCTL, sizeof(b), &b, EC_TIMEOUTRET3);       /* Reset all slaves to Init */
00131    /* netX100 should now be happy */
00132    ecx_BWR(context->port, 0x0000, ECT_REG_ALCTL, sizeof(b), &b, EC_TIMEOUTRET3);       /* Reset all slaves to Init */
00133    wkc = ecx_BRD(context->port, 0x0000, ECT_REG_TYPE, sizeof(w), &w, EC_TIMEOUTSAFE);  /* detect number of slaves */
00134    if (wkc > 0)
00135    {
00136       /* this is strictly "less than" since the master is "slave 0" */
00137       if (wkc < EC_MAXSLAVE)
00138       {
00139          *(context->slavecount) = wkc;
00140       }
00141       else
00142       {
00143          EC_PRINT("Error: too many slaves on network: num_slaves=%d, EC_MAXSLAVE=%d\n",
00144                wkc, EC_MAXSLAVE);
00145          return -2;
00146       }
00147    }
00148    return wkc;
00149 }
00150 
00151 static void ecx_set_slaves_to_default(ecx_contextt *context)
00152 {
00153    uint8 b;
00154    uint16 w;
00155    uint8 zbuf[64];
00156    memset(&zbuf, 0x00, sizeof(zbuf));
00157    b = 0x00;
00158    ecx_BWR(context->port, 0x0000, ECT_REG_DLPORT      , sizeof(b) , &b, EC_TIMEOUTRET3);     /* deact loop manual */
00159    w = htoes(0x0004);
00160    ecx_BWR(context->port, 0x0000, ECT_REG_IRQMASK     , sizeof(w) , &w, EC_TIMEOUTRET3);     /* set IRQ mask */
00161    ecx_BWR(context->port, 0x0000, ECT_REG_RXERR       , 8         , &zbuf, EC_TIMEOUTRET3);  /* reset CRC counters */
00162    ecx_BWR(context->port, 0x0000, ECT_REG_FMMU0       , 16 * 3    , &zbuf, EC_TIMEOUTRET3);  /* reset FMMU's */
00163    ecx_BWR(context->port, 0x0000, ECT_REG_SM0         , 8 * 4     , &zbuf, EC_TIMEOUTRET3);  /* reset SyncM */
00164    b = 0x00;
00165    ecx_BWR(context->port, 0x0000, ECT_REG_DCSYNCACT   , sizeof(b) , &b, EC_TIMEOUTRET3);     /* reset activation register */
00166    ecx_BWR(context->port, 0x0000, ECT_REG_DCSYSTIME   , 4         , &zbuf, EC_TIMEOUTRET3);  /* reset system time+ofs */
00167    w = htoes(0x1000);
00168    ecx_BWR(context->port, 0x0000, ECT_REG_DCSPEEDCNT  , sizeof(w) , &w, EC_TIMEOUTRET3);     /* DC speedstart */
00169    w = htoes(0x0c00);
00170    ecx_BWR(context->port, 0x0000, ECT_REG_DCTIMEFILT  , sizeof(w) , &w, EC_TIMEOUTRET3);     /* DC filt expr */
00171    b = 0x00;
00172    ecx_BWR(context->port, 0x0000, ECT_REG_DLALIAS     , sizeof(b) , &b, EC_TIMEOUTRET3);     /* Ignore Alias register */
00173    b = EC_STATE_INIT | EC_STATE_ACK;
00174    ecx_BWR(context->port, 0x0000, ECT_REG_ALCTL       , sizeof(b) , &b, EC_TIMEOUTRET3);     /* Reset all slaves to Init */
00175    b = 2;
00176    ecx_BWR(context->port, 0x0000, ECT_REG_EEPCFG      , sizeof(b) , &b, EC_TIMEOUTRET3);     /* force Eeprom from PDI */
00177    b = 0;
00178    ecx_BWR(context->port, 0x0000, ECT_REG_EEPCFG      , sizeof(b) , &b, EC_TIMEOUTRET3);     /* set Eeprom to master */
00179 }
00180 
00181 #ifdef EC_VER1
00182 static int ecx_config_from_table(ecx_contextt *context, uint16 slave)
00183 {
00184    int cindex;
00185    ec_slavet *csl;
00186 
00187    csl = &(context->slavelist[slave]);
00188    cindex = ec_findconfig( csl->eep_man, csl->eep_id );
00189    csl->configindex= cindex;
00190    /* slave found in configuration table ? */
00191    if (cindex)
00192    {
00193       csl->Dtype = ec_configlist[cindex].Dtype;
00194       strcpy(csl->name ,ec_configlist[cindex].name);
00195       csl->Ibits = ec_configlist[cindex].Ibits;
00196       csl->Obits = ec_configlist[cindex].Obits;
00197       if (csl->Obits)
00198       {
00199          csl->FMMU0func = 1;
00200       }
00201       if (csl->Ibits)
00202       {
00203          csl->FMMU1func = 2;
00204       }
00205       csl->FMMU[0].FMMUactive = ec_configlist[cindex].FM0ac;
00206       csl->FMMU[1].FMMUactive = ec_configlist[cindex].FM1ac;
00207       csl->SM[2].StartAddr = htoes(ec_configlist[cindex].SM2a);
00208       csl->SM[2].SMflags = htoel(ec_configlist[cindex].SM2f);
00209       /* simple (no mailbox) output slave found ? */
00210       if (csl->Obits && !csl->SM[2].StartAddr)
00211       {
00212          csl->SM[0].StartAddr = htoes(0x0f00);
00213          csl->SM[0].SMlength = htoes((csl->Obits + 7) / 8);
00214          csl->SM[0].SMflags = htoel(EC_DEFAULTDOSM0);
00215          csl->FMMU[0].FMMUactive = 1;
00216          csl->FMMU[0].FMMUtype = 2;
00217          csl->SMtype[0] = 3;
00218       }
00219       /* complex output slave */
00220       else
00221       {
00222          csl->SM[2].SMlength = htoes((csl->Obits + 7) / 8);
00223          csl->SMtype[2] = 3;
00224       }
00225       csl->SM[3].StartAddr = htoes(ec_configlist[cindex].SM3a);
00226       csl->SM[3].SMflags = htoel(ec_configlist[cindex].SM3f);
00227       /* simple (no mailbox) input slave found ? */
00228       if (csl->Ibits && !csl->SM[3].StartAddr)
00229       {
00230          csl->SM[1].StartAddr = htoes(0x1000);
00231          csl->SM[1].SMlength = htoes((csl->Ibits + 7) / 8);
00232          csl->SM[1].SMflags = htoel(0x00000000);
00233          csl->FMMU[1].FMMUactive = 1;
00234          csl->FMMU[1].FMMUtype = 1;
00235          csl->SMtype[1] = 4;
00236       }
00237       /* complex input slave */
00238       else
00239       {
00240          csl->SM[3].SMlength = htoes((csl->Ibits + 7) / 8);
00241          csl->SMtype[3] = 4;
00242       }
00243    }
00244    return cindex;
00245 }
00246 #else
00247 static int ecx_config_from_table(ecx_contextt *context, uint16 slave)
00248 {
00249    (void)context;
00250    (void)slave;
00251    return 0;
00252 }
00253 #endif
00254 
00255 /* If slave has SII and same slave ID done before, use previous data.
00256  * This is safe because SII is constant for same slave ID.
00257  */
00258 static int ecx_lookup_prev_sii(ecx_contextt *context, uint16 slave)
00259 {
00260    int i, nSM;
00261    if ((slave > 1) && (*(context->slavecount) > 0))
00262    {
00263       i = 1;
00264       while(((context->slavelist[i].eep_man != context->slavelist[slave].eep_man) ||
00265              (context->slavelist[i].eep_id  != context->slavelist[slave].eep_id ) ||
00266              (context->slavelist[i].eep_rev != context->slavelist[slave].eep_rev)) &&
00267             (i < slave))
00268       {
00269          i++;
00270       }
00271       if(i < slave)
00272       {
00273          context->slavelist[slave].CoEdetails = context->slavelist[i].CoEdetails;
00274          context->slavelist[slave].FoEdetails = context->slavelist[i].FoEdetails;
00275          context->slavelist[slave].EoEdetails = context->slavelist[i].EoEdetails;
00276          context->slavelist[slave].SoEdetails = context->slavelist[i].SoEdetails;
00277          if(context->slavelist[i].blockLRW > 0)
00278          {
00279             context->slavelist[slave].blockLRW = 1;
00280             context->slavelist[0].blockLRW++;
00281          }
00282          context->slavelist[slave].Ebuscurrent = context->slavelist[i].Ebuscurrent;
00283          context->slavelist[0].Ebuscurrent += context->slavelist[slave].Ebuscurrent;
00284          memcpy(context->slavelist[slave].name, context->slavelist[i].name, EC_MAXNAME + 1);
00285          for( nSM=0 ; nSM < EC_MAXSM ; nSM++ )
00286          {
00287             context->slavelist[slave].SM[nSM].StartAddr = context->slavelist[i].SM[nSM].StartAddr;
00288             context->slavelist[slave].SM[nSM].SMlength  = context->slavelist[i].SM[nSM].SMlength;
00289             context->slavelist[slave].SM[nSM].SMflags   = context->slavelist[i].SM[nSM].SMflags;
00290          }
00291          context->slavelist[slave].FMMU0func = context->slavelist[i].FMMU0func;
00292          context->slavelist[slave].FMMU1func = context->slavelist[i].FMMU1func;
00293          context->slavelist[slave].FMMU2func = context->slavelist[i].FMMU2func;
00294          context->slavelist[slave].FMMU3func = context->slavelist[i].FMMU3func;
00295          EC_PRINT("Copy SII slave %d from %d.\n", slave, i);
00296          return 1;
00297       }
00298    }
00299    return 0;
00300 }
00301 
00302 /** Enumerate and init all slaves.
00303  *
00304  * @param[in] context      = context struct
00305  * @param[in] usetable     = TRUE when using configtable to init slaves, FALSE otherwise
00306  * @return Workcounter of slave discover datagram = number of slaves found
00307  */
00308 int ecx_config_init(ecx_contextt *context, uint8 usetable)
00309 {
00310    uint16 slave, ADPh, configadr, ssigen;
00311    uint16 topology, estat;
00312    int16 topoc, slavec, aliasadr;
00313    uint8 b,h;
00314    uint8 SMc;
00315    uint32 eedat;
00316    int wkc, cindex, nSM;
00317    uint16 val16;
00318 
00319    EC_PRINT("ec_config_init %d\n",usetable);
00320    ecx_init_context(context);
00321    wkc = ecx_detect_slaves(context);
00322    if (wkc > 0)
00323    {
00324       ecx_set_slaves_to_default(context);
00325       for (slave = 1; slave <= *(context->slavecount); slave++)
00326       {
00327          ADPh = (uint16)(1 - slave);
00328          val16 = ecx_APRDw(context->port, ADPh, ECT_REG_PDICTL, EC_TIMEOUTRET3); /* read interface type of slave */
00329          context->slavelist[slave].Itype = etohs(val16);
00330          /* a node offset is used to improve readability of network frames */
00331          /* this has no impact on the number of addressable slaves (auto wrap around) */
00332          ecx_APWRw(context->port, ADPh, ECT_REG_STADR, htoes(slave + EC_NODEOFFSET) , EC_TIMEOUTRET3); /* set node address of slave */
00333          if (slave == 1)
00334          {
00335             b = 1; /* kill non ecat frames for first slave */
00336          }
00337          else
00338          {
00339             b = 0; /* pass all frames for following slaves */
00340          }
00341          ecx_APWRw(context->port, ADPh, ECT_REG_DLCTL, htoes(b), EC_TIMEOUTRET3); /* set non ecat frame behaviour */
00342          configadr = ecx_APRDw(context->port, ADPh, ECT_REG_STADR, EC_TIMEOUTRET3);
00343          configadr = etohs(configadr);
00344          context->slavelist[slave].configadr = configadr;
00345          ecx_FPRD(context->port, configadr, ECT_REG_ALIAS, sizeof(aliasadr), &aliasadr, EC_TIMEOUTRET3);
00346          context->slavelist[slave].aliasadr = etohs(aliasadr);
00347          ecx_FPRD(context->port, configadr, ECT_REG_EEPSTAT, sizeof(estat), &estat, EC_TIMEOUTRET3);
00348          estat = etohs(estat);
00349          if (estat & EC_ESTAT_R64) /* check if slave can read 8 byte chunks */
00350          {
00351             context->slavelist[slave].eep_8byte = 1;
00352          }
00353          ecx_readeeprom1(context, slave, ECT_SII_MANUF); /* Manuf */
00354       }
00355       for (slave = 1; slave <= *(context->slavecount); slave++)
00356       {
00357          eedat = ecx_readeeprom2(context, slave, EC_TIMEOUTEEP); /* Manuf */
00358          context->slavelist[slave].eep_man = etohl(eedat);
00359          ecx_readeeprom1(context, slave, ECT_SII_ID); /* ID */
00360       }
00361       for (slave = 1; slave <= *(context->slavecount); slave++)
00362       {
00363          eedat = ecx_readeeprom2(context, slave, EC_TIMEOUTEEP); /* ID */
00364          context->slavelist[slave].eep_id = etohl(eedat);
00365          ecx_readeeprom1(context, slave, ECT_SII_REV); /* revision */
00366       }
00367       for (slave = 1; slave <= *(context->slavecount); slave++)
00368       {
00369          eedat = ecx_readeeprom2(context, slave, EC_TIMEOUTEEP); /* revision */
00370          context->slavelist[slave].eep_rev = etohl(eedat);
00371          ecx_readeeprom1(context, slave, ECT_SII_RXMBXADR); /* write mailbox address + mailboxsize */
00372       }
00373       for (slave = 1; slave <= *(context->slavecount); slave++)
00374       {
00375          eedat = ecx_readeeprom2(context, slave, EC_TIMEOUTEEP); /* write mailbox address and mailboxsize */
00376          context->slavelist[slave].mbx_wo = (uint16)LO_WORD(etohl(eedat));
00377          context->slavelist[slave].mbx_l = (uint16)HI_WORD(etohl(eedat));
00378          if (context->slavelist[slave].mbx_l > 0)
00379          {
00380             ecx_readeeprom1(context, slave, ECT_SII_TXMBXADR); /* read mailbox offset */
00381          }
00382       }
00383       for (slave = 1; slave <= *(context->slavecount); slave++)
00384       {
00385          if (context->slavelist[slave].mbx_l > 0)
00386          {
00387             eedat = ecx_readeeprom2(context, slave, EC_TIMEOUTEEP); /* read mailbox offset */
00388             context->slavelist[slave].mbx_ro = (uint16)LO_WORD(etohl(eedat)); /* read mailbox offset */
00389             context->slavelist[slave].mbx_rl = (uint16)HI_WORD(etohl(eedat)); /*read mailbox length */
00390             if (context->slavelist[slave].mbx_rl == 0)
00391             {
00392                context->slavelist[slave].mbx_rl = context->slavelist[slave].mbx_l;
00393             }
00394             ecx_readeeprom1(context, slave, ECT_SII_MBXPROTO);
00395          }
00396          configadr = context->slavelist[slave].configadr;
00397          val16 = ecx_FPRDw(context->port, configadr, ECT_REG_ESCSUP, EC_TIMEOUTRET3);
00398          if ((etohs(val16) & 0x04) > 0)  /* Support DC? */
00399          {
00400             context->slavelist[slave].hasdc = TRUE;
00401          }
00402          else
00403          {
00404             context->slavelist[slave].hasdc = FALSE;
00405          }
00406          topology = ecx_FPRDw(context->port, configadr, ECT_REG_DLSTAT, EC_TIMEOUTRET3); /* extract topology from DL status */
00407          topology = etohs(topology);
00408          h = 0;
00409          b = 0;
00410          if ((topology & 0x0300) == 0x0200) /* port0 open and communication established */
00411          {
00412             h++;
00413             b |= 0x01;
00414          }
00415          if ((topology & 0x0c00) == 0x0800) /* port1 open and communication established */
00416          {
00417             h++;
00418             b |= 0x02;
00419          }
00420          if ((topology & 0x3000) == 0x2000) /* port2 open and communication established */
00421          {
00422             h++;
00423             b |= 0x04;
00424          }
00425          if ((topology & 0xc000) == 0x8000) /* port3 open and communication established */
00426          {
00427             h++;
00428             b |= 0x08;
00429          }
00430          /* ptype = Physical type*/
00431          val16 = ecx_FPRDw(context->port, configadr, ECT_REG_PORTDES, EC_TIMEOUTRET3);
00432          context->slavelist[slave].ptype = LO_BYTE(etohs(val16));
00433          context->slavelist[slave].topology = h;
00434          context->slavelist[slave].activeports = b;
00435          /* 0=no links, not possible             */
00436          /* 1=1 link  , end of line              */
00437          /* 2=2 links , one before and one after */
00438          /* 3=3 links , split point              */
00439          /* 4=4 links , cross point              */
00440          /* search for parent */
00441          context->slavelist[slave].parent = 0; /* parent is master */
00442          if (slave > 1)
00443          {
00444             topoc = 0;
00445             slavec = slave - 1;
00446             do
00447             {
00448                topology = context->slavelist[slavec].topology;
00449                if (topology == 1)
00450                {
00451                   topoc--; /* endpoint found */
00452                }
00453                if (topology == 3)
00454                {
00455                   topoc++; /* split found */
00456                }
00457                if (topology == 4)
00458                {
00459                   topoc += 2; /* cross found */
00460                }
00461                if (((topoc >= 0) && (topology > 1)) ||
00462                    (slavec == 1)) /* parent found */
00463                {
00464                   context->slavelist[slave].parent = slavec;
00465                   slavec = 1;
00466                }
00467                slavec--;
00468             }
00469             while (slavec > 0);
00470          }
00471          (void)ecx_statecheck(context, slave, EC_STATE_INIT,  EC_TIMEOUTSTATE); //* check state change Init */
00472 
00473          /* set default mailbox configuration if slave has mailbox */
00474          if (context->slavelist[slave].mbx_l>0)
00475          {
00476             context->slavelist[slave].SMtype[0] = 1;
00477             context->slavelist[slave].SMtype[1] = 2;
00478             context->slavelist[slave].SMtype[2] = 3;
00479             context->slavelist[slave].SMtype[3] = 4;
00480             context->slavelist[slave].SM[0].StartAddr = htoes(context->slavelist[slave].mbx_wo);
00481             context->slavelist[slave].SM[0].SMlength = htoes(context->slavelist[slave].mbx_l);
00482             context->slavelist[slave].SM[0].SMflags = htoel(EC_DEFAULTMBXSM0);
00483             context->slavelist[slave].SM[1].StartAddr = htoes(context->slavelist[slave].mbx_ro);
00484             context->slavelist[slave].SM[1].SMlength = htoes(context->slavelist[slave].mbx_rl);
00485             context->slavelist[slave].SM[1].SMflags = htoel(EC_DEFAULTMBXSM1);
00486             eedat = ecx_readeeprom2(context, slave, EC_TIMEOUTEEP);
00487             context->slavelist[slave].mbx_proto = etohl(eedat);
00488          }
00489          cindex = 0;
00490          /* use configuration table ? */
00491          if (usetable == 1)
00492          {
00493             cindex = ecx_config_from_table(context, slave);
00494          }
00495          /* slave not in configuration table, find out via SII */
00496          if (!cindex && !ecx_lookup_prev_sii(context, slave))
00497          {
00498             ssigen = ecx_siifind(context, slave, ECT_SII_GENERAL);
00499             /* SII general section */
00500             if (ssigen)
00501             {
00502                context->slavelist[slave].CoEdetails = ecx_siigetbyte(context, slave, ssigen + 0x07);
00503                context->slavelist[slave].FoEdetails = ecx_siigetbyte(context, slave, ssigen + 0x08);
00504                context->slavelist[slave].EoEdetails = ecx_siigetbyte(context, slave, ssigen + 0x09);
00505                context->slavelist[slave].SoEdetails = ecx_siigetbyte(context, slave, ssigen + 0x0a);
00506                if((ecx_siigetbyte(context, slave, ssigen + 0x0d) & 0x02) > 0)
00507                {
00508                   context->slavelist[slave].blockLRW = 1;
00509                   context->slavelist[0].blockLRW++;
00510                }
00511                context->slavelist[slave].Ebuscurrent = ecx_siigetbyte(context, slave, ssigen + 0x0e);
00512                context->slavelist[slave].Ebuscurrent += ecx_siigetbyte(context, slave, ssigen + 0x0f) << 8;
00513                context->slavelist[0].Ebuscurrent += context->slavelist[slave].Ebuscurrent;
00514             }
00515             /* SII strings section */
00516             if (ecx_siifind(context, slave, ECT_SII_STRING) > 0)
00517             {
00518                ecx_siistring(context, context->slavelist[slave].name, slave, 1);
00519             }
00520             /* no name for slave found, use constructed name */
00521             else
00522             {
00523                sprintf(context->slavelist[slave].name, "? M:%8.8x I:%8.8x",
00524                        (unsigned int)context->slavelist[slave].eep_man,
00525                        (unsigned int)context->slavelist[slave].eep_id);
00526             }
00527             /* SII SM section */
00528             nSM = ecx_siiSM(context, slave, context->eepSM);
00529             if (nSM>0)
00530             {
00531                context->slavelist[slave].SM[0].StartAddr = htoes(context->eepSM->PhStart);
00532                context->slavelist[slave].SM[0].SMlength = htoes(context->eepSM->Plength);
00533                context->slavelist[slave].SM[0].SMflags =
00534                   htoel((context->eepSM->Creg) + (context->eepSM->Activate << 16));
00535                SMc = 1;
00536                while ((SMc < EC_MAXSM) &&  ecx_siiSMnext(context, slave, context->eepSM, SMc))
00537                {
00538                   context->slavelist[slave].SM[SMc].StartAddr = htoes(context->eepSM->PhStart);
00539                   context->slavelist[slave].SM[SMc].SMlength = htoes(context->eepSM->Plength);
00540                   context->slavelist[slave].SM[SMc].SMflags =
00541                      htoel((context->eepSM->Creg) + (context->eepSM->Activate << 16));
00542                   SMc++;
00543                }
00544             }
00545             /* SII FMMU section */
00546             if (ecx_siiFMMU(context, slave, context->eepFMMU))
00547             {
00548                if (context->eepFMMU->FMMU0 !=0xff)
00549                {
00550                   context->slavelist[slave].FMMU0func = context->eepFMMU->FMMU0;
00551                }
00552                if (context->eepFMMU->FMMU1 !=0xff)
00553                {
00554                   context->slavelist[slave].FMMU1func = context->eepFMMU->FMMU1;
00555                }
00556                if (context->eepFMMU->FMMU2 !=0xff)
00557                {
00558                   context->slavelist[slave].FMMU2func = context->eepFMMU->FMMU2;
00559                }
00560                if (context->eepFMMU->FMMU3 !=0xff)
00561                {
00562                   context->slavelist[slave].FMMU3func = context->eepFMMU->FMMU3;
00563                }
00564             }
00565          }
00566 
00567          if (context->slavelist[slave].mbx_l > 0)
00568          {
00569             if (context->slavelist[slave].SM[0].StartAddr == 0x0000) /* should never happen */
00570             {
00571                EC_PRINT("Slave %d has no proper mailbox in configuration, try default.\n", slave);
00572                context->slavelist[slave].SM[0].StartAddr = htoes(0x1000);
00573                context->slavelist[slave].SM[0].SMlength = htoes(0x0080);
00574                context->slavelist[slave].SM[0].SMflags = htoel(EC_DEFAULTMBXSM0);
00575                context->slavelist[slave].SMtype[0] = 1;
00576             }
00577             if (context->slavelist[slave].SM[1].StartAddr == 0x0000) /* should never happen */
00578             {
00579                EC_PRINT("Slave %d has no proper mailbox out configuration, try default.\n", slave);
00580                context->slavelist[slave].SM[1].StartAddr = htoes(0x1080);
00581                context->slavelist[slave].SM[1].SMlength = htoes(0x0080);
00582                context->slavelist[slave].SM[1].SMflags = htoel(EC_DEFAULTMBXSM1);
00583                context->slavelist[slave].SMtype[1] = 2;
00584             }
00585             /* program SM0 mailbox in and SM1 mailbox out for slave */
00586             /* writing both SM in one datagram will solve timing issue in old NETX */
00587             ecx_FPWR(context->port, configadr, ECT_REG_SM0, sizeof(ec_smt) * 2,
00588                &(context->slavelist[slave].SM[0]), EC_TIMEOUTRET3);
00589          }
00590          /* some slaves need eeprom available to PDI in init->preop transition */
00591          ecx_eeprom2pdi(context, slave);
00592          /* request pre_op for slave */
00593          ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_PRE_OP | EC_STATE_ACK) , EC_TIMEOUTRET3); /* set preop status */
00594       }
00595    }
00596    return wkc;
00597 }
00598 
00599 /* If slave has SII mapping and same slave ID done before, use previous mapping.
00600  * This is safe because SII mapping is constant for same slave ID.
00601  */
00602 static int ecx_lookup_mapping(ecx_contextt *context, uint16 slave, int *Osize, int *Isize)
00603 {
00604    int i, nSM;
00605    if ((slave > 1) && (*(context->slavecount) > 0))
00606    {
00607       i = 1;
00608       while(((context->slavelist[i].eep_man != context->slavelist[slave].eep_man) ||
00609              (context->slavelist[i].eep_id  != context->slavelist[slave].eep_id ) ||
00610              (context->slavelist[i].eep_rev != context->slavelist[slave].eep_rev)) &&
00611             (i < slave))
00612       {
00613          i++;
00614       }
00615       if(i < slave)
00616       {
00617          for( nSM=0 ; nSM < EC_MAXSM ; nSM++ )
00618          {
00619             context->slavelist[slave].SM[nSM].SMlength = context->slavelist[i].SM[nSM].SMlength;
00620             context->slavelist[slave].SMtype[nSM] = context->slavelist[i].SMtype[nSM];
00621          }
00622          *Osize = context->slavelist[i].Obits;
00623          *Isize = context->slavelist[i].Ibits;
00624          context->slavelist[slave].Obits = *Osize;
00625          context->slavelist[slave].Ibits = *Isize;
00626          EC_PRINT("Copy mapping slave %d from %d.\n", slave, i);
00627          return 1;
00628       }
00629    }
00630    return 0;
00631 }
00632 
00633 static int ecx_map_coe_soe(ecx_contextt *context, uint16 slave, int thread_n)
00634 {
00635    int Isize, Osize;
00636    int rval;
00637 
00638    ecx_statecheck(context, slave, EC_STATE_PRE_OP, EC_TIMEOUTSTATE); /* check state change pre-op */
00639 
00640    EC_PRINT(" >Slave %d, configadr %x, state %2.2x\n",
00641             slave, context->slavelist[slave].configadr, context->slavelist[slave].state);
00642 
00643    /* execute special slave configuration hook Pre-Op to Safe-OP */
00644    if(context->slavelist[slave].PO2SOconfig) /* only if registered */
00645    {
00646       context->slavelist[slave].PO2SOconfig(slave);
00647    }
00648    /* if slave not found in configlist find IO mapping in slave self */
00649    if (!context->slavelist[slave].configindex)
00650    {
00651       Isize = 0;
00652       Osize = 0;
00653       if (context->slavelist[slave].mbx_proto & ECT_MBXPROT_COE) /* has CoE */
00654       {
00655          rval = 0;
00656          if (context->slavelist[slave].CoEdetails & ECT_COEDET_SDOCA) /* has Complete Access */
00657          {
00658             /* read PDO mapping via CoE and use Complete Access */
00659             rval = ecx_readPDOmapCA(context, slave, thread_n, &Osize, &Isize);
00660          }
00661          if (!rval) /* CA not available or not succeeded */
00662          {
00663             /* read PDO mapping via CoE */
00664             rval = ecx_readPDOmap(context, slave, &Osize, &Isize);
00665          }
00666          EC_PRINT("  CoE Osize:%d Isize:%d\n", Osize, Isize);
00667       }
00668       if ((!Isize && !Osize) && (context->slavelist[slave].mbx_proto & ECT_MBXPROT_SOE)) /* has SoE */
00669       {
00670          /* read AT / MDT mapping via SoE */
00671          rval = ecx_readIDNmap(context, slave, &Osize, &Isize);
00672          context->slavelist[slave].SM[2].SMlength = htoes((Osize + 7) / 8);
00673          context->slavelist[slave].SM[3].SMlength = htoes((Isize + 7) / 8);
00674          EC_PRINT("  SoE Osize:%d Isize:%d\n", Osize, Isize);
00675       }
00676       context->slavelist[slave].Obits = Osize;
00677       context->slavelist[slave].Ibits = Isize;
00678    }
00679 
00680    return 1;
00681 }
00682 
00683 static int ecx_map_sii(ecx_contextt *context, uint16 slave)
00684 {
00685    int Isize, Osize;
00686    int nSM;
00687    ec_eepromPDOt eepPDO;
00688 
00689    Osize = context->slavelist[slave].Obits;
00690    Isize = context->slavelist[slave].Ibits;
00691 
00692    if (!Isize && !Osize) /* find PDO in previous slave with same ID */
00693    {
00694       (void)ecx_lookup_mapping(context, slave, &Osize, &Isize);
00695    }
00696    if (!Isize && !Osize) /* find PDO mapping by SII */
00697    {
00698       memset(&eepPDO, 0, sizeof(eepPDO));
00699       Isize = (int)ecx_siiPDO(context, slave, &eepPDO, 0);
00700       EC_PRINT("  SII Isize:%d\n", Isize);
00701       for( nSM=0 ; nSM < EC_MAXSM ; nSM++ )
00702       {
00703          if (eepPDO.SMbitsize[nSM] > 0)
00704          {
00705             context->slavelist[slave].SM[nSM].SMlength =  htoes((eepPDO.SMbitsize[nSM] + 7) / 8);
00706             context->slavelist[slave].SMtype[nSM] = 4;
00707             EC_PRINT("    SM%d length %d\n", nSM, eepPDO.SMbitsize[nSM]);
00708          }
00709       }
00710       Osize = (int)ecx_siiPDO(context, slave, &eepPDO, 1);
00711       EC_PRINT("  SII Osize:%d\n", Osize);
00712       for( nSM=0 ; nSM < EC_MAXSM ; nSM++ )
00713       {
00714          if (eepPDO.SMbitsize[nSM] > 0)
00715          {
00716             context->slavelist[slave].SM[nSM].SMlength =  htoes((eepPDO.SMbitsize[nSM] + 7) / 8);
00717             context->slavelist[slave].SMtype[nSM] = 3;
00718             EC_PRINT("    SM%d length %d\n", nSM, eepPDO.SMbitsize[nSM]);
00719          }
00720       }
00721    }
00722    context->slavelist[slave].Obits = Osize;
00723    context->slavelist[slave].Ibits = Isize;
00724    EC_PRINT("     ISIZE:%d %d OSIZE:%d\n",
00725       context->slavelist[slave].Ibits, Isize,context->slavelist[slave].Obits);
00726 
00727    return 1;
00728 }
00729 
00730 static int ecx_map_sm(ecx_contextt *context, uint16 slave)
00731 {
00732    uint16 configadr;
00733    int nSM;
00734 
00735    configadr = context->slavelist[slave].configadr;
00736 
00737    EC_PRINT("  SM programming\n");
00738    if (!context->slavelist[slave].mbx_l && context->slavelist[slave].SM[0].StartAddr)
00739    {
00740       ecx_FPWR(context->port, configadr, ECT_REG_SM0,
00741          sizeof(ec_smt), &(context->slavelist[slave].SM[0]), EC_TIMEOUTRET3);
00742       EC_PRINT("    SM0 Type:%d StartAddr:%4.4x Flags:%8.8x\n",
00743           context->slavelist[slave].SMtype[0],
00744           context->slavelist[slave].SM[0].StartAddr,
00745           context->slavelist[slave].SM[0].SMflags);
00746    }
00747    if (!context->slavelist[slave].mbx_l && context->slavelist[slave].SM[1].StartAddr)
00748    {
00749       ecx_FPWR(context->port, configadr, ECT_REG_SM1,
00750          sizeof(ec_smt), &context->slavelist[slave].SM[1], EC_TIMEOUTRET3);
00751       EC_PRINT("    SM1 Type:%d StartAddr:%4.4x Flags:%8.8x\n",
00752           context->slavelist[slave].SMtype[1],
00753           context->slavelist[slave].SM[1].StartAddr,
00754           context->slavelist[slave].SM[1].SMflags);
00755    }
00756    /* program SM2 to SMx */
00757    for( nSM = 2 ; nSM < EC_MAXSM ; nSM++ )
00758    {
00759       if (context->slavelist[slave].SM[nSM].StartAddr)
00760       {
00761          /* check if SM length is zero -> clear enable flag */
00762          if( context->slavelist[slave].SM[nSM].SMlength == 0)
00763          {
00764             context->slavelist[slave].SM[nSM].SMflags =
00765                htoel( etohl(context->slavelist[slave].SM[nSM].SMflags) & EC_SMENABLEMASK);
00766          }
00767          /* if SM length is non zero always set enable flag */
00768          else
00769          {
00770             context->slavelist[slave].SM[nSM].SMflags =
00771                htoel( etohl(context->slavelist[slave].SM[nSM].SMflags) | ~EC_SMENABLEMASK);
00772          }
00773          ecx_FPWR(context->port, configadr, (uint16)(ECT_REG_SM0 + (nSM * sizeof(ec_smt))),
00774             sizeof(ec_smt), &context->slavelist[slave].SM[nSM], EC_TIMEOUTRET3);
00775          EC_PRINT("    SM%d Type:%d StartAddr:%4.4x Flags:%8.8x\n", nSM,
00776              context->slavelist[slave].SMtype[nSM],
00777              context->slavelist[slave].SM[nSM].StartAddr,
00778              context->slavelist[slave].SM[nSM].SMflags);
00779       }
00780    }
00781    if (context->slavelist[slave].Ibits > 7)
00782    {
00783       context->slavelist[slave].Ibytes = (context->slavelist[slave].Ibits + 7) / 8;
00784    }
00785    if (context->slavelist[slave].Obits > 7)
00786    {
00787       context->slavelist[slave].Obytes = (context->slavelist[slave].Obits + 7) / 8;
00788    }
00789 
00790    return 1;
00791 }
00792 
00793 #if EC_MAX_MAPT > 1
00794 OSAL_THREAD_FUNC ecx_mapper_thread(void *param)
00795 {
00796    ecx_mapt_t *maptp;
00797    maptp = param;
00798    ecx_map_coe_soe(maptp->context, maptp->slave, maptp->thread_n);
00799    maptp->running = 0;
00800 }
00801 
00802 static int ecx_find_mapt(void)
00803 {
00804    int p;
00805    p = 0;
00806    while((p < EC_MAX_MAPT) && ecx_mapt[p].running)
00807    {
00808       p++;
00809    }
00810    if(p < EC_MAX_MAPT)
00811    {
00812       return p;
00813    }
00814    else
00815    {
00816       return -1;
00817    }
00818 }
00819 #endif
00820 
00821 static int ecx_get_threadcount(void)
00822 {
00823    int thrc, thrn;
00824    thrc = 0;
00825    for(thrn = 0 ; thrn < EC_MAX_MAPT ; thrn++)
00826    {
00827       thrc += ecx_mapt[thrn].running;
00828    }
00829    return thrc;
00830 }
00831 
00832 static void ecx_config_find_mappings(ecx_contextt *context, uint8 group)
00833 {
00834    int thrn, thrc;
00835    uint16 slave;
00836 
00837    for (thrn = 0; thrn < EC_MAX_MAPT; thrn++)
00838    {
00839       ecx_mapt[thrn].running = 0;
00840    }
00841    /* find CoE and SoE mapping of slaves in multiple threads */
00842    for (slave = 1; slave <= *(context->slavecount); slave++)
00843    {
00844       if (!group || (group == context->slavelist[slave].group))
00845       {
00846 #if EC_MAX_MAPT > 1
00847             /* multi-threaded version */
00848             while ((thrn = ecx_find_mapt()) < 0)
00849             {
00850                osal_usleep(1000);
00851             }
00852             ecx_mapt[thrn].context = context;
00853             ecx_mapt[thrn].slave = slave;
00854             ecx_mapt[thrn].thread_n = thrn;
00855             ecx_mapt[thrn].running = 1;
00856             osal_thread_create(&(ecx_threadh[thrn]), 128000,
00857                &ecx_mapper_thread, &(ecx_mapt[thrn]));
00858 #else
00859             /* serialised version */
00860             ecx_map_coe_soe(context, slave, 0);
00861 #endif
00862       }
00863    }
00864    /* wait for all threads to finish */
00865    do
00866    {
00867       thrc = ecx_get_threadcount();
00868       if (thrc)
00869       {
00870          osal_usleep(1000);
00871       }
00872    } while (thrc);
00873    /* find SII mapping of slave and program SM */
00874    for (slave = 1; slave <= *(context->slavecount); slave++)
00875    {
00876       if (!group || (group == context->slavelist[slave].group))
00877       {
00878          ecx_map_sii(context, slave);
00879          ecx_map_sm(context, slave);
00880       }
00881    }
00882 }
00883 
00884 static void ecx_config_create_input_mappings(ecx_contextt *context, void *pIOmap, 
00885    uint8 group, int16 slave, uint32 * LogAddr, uint8 * BitPos)
00886 {
00887    int BitCount = 0;
00888    int ByteCount = 0;
00889    int FMMUsize = 0;
00890    int FMMUdone = 0;
00891    uint8 SMc = 0;
00892    uint16 EndAddr;
00893    uint16 SMlength;
00894    uint16 configadr;
00895    uint8 FMMUc;
00896 
00897    EC_PRINT(" =Slave %d, INPUT MAPPING\n", slave);
00898 
00899    configadr = context->slavelist[slave].configadr;
00900    FMMUc = context->slavelist[slave].FMMUunused;
00901    if (context->slavelist[slave].Obits) /* find free FMMU */
00902    {
00903       while (context->slavelist[slave].FMMU[FMMUc].LogStart)
00904       {
00905          FMMUc++;
00906       }
00907    }
00908    /* search for SM that contribute to the input mapping */
00909    while ((SMc < (EC_MAXSM - 1)) && (FMMUdone < ((context->slavelist[slave].Ibits + 7) / 8)))
00910    {
00911       EC_PRINT("    FMMU %d\n", FMMUc);
00912       while ((SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 4))
00913       {
00914          SMc++;
00915       }
00916       EC_PRINT("      SM%d\n", SMc);
00917       context->slavelist[slave].FMMU[FMMUc].PhysStart =
00918          context->slavelist[slave].SM[SMc].StartAddr;
00919       SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength);
00920       ByteCount += SMlength;
00921       BitCount += SMlength * 8;
00922       EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength;
00923       while ((BitCount < context->slavelist[slave].Ibits) && (SMc < (EC_MAXSM - 1))) /* more SM for input */
00924       {
00925          SMc++;
00926          while ((SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 4))
00927          {
00928             SMc++;
00929          }
00930          /* if addresses from more SM connect use one FMMU otherwise break up in multiple FMMU */
00931          if (etohs(context->slavelist[slave].SM[SMc].StartAddr) > EndAddr)
00932          {
00933             break;
00934          }
00935          EC_PRINT("      SM%d\n", SMc);
00936          SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength);
00937          ByteCount += SMlength;
00938          BitCount += SMlength * 8;
00939          EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength;
00940       }
00941 
00942       /* bit oriented slave */
00943       if (!context->slavelist[slave].Ibytes)
00944       {
00945          context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(*LogAddr);
00946          context->slavelist[slave].FMMU[FMMUc].LogStartbit = *BitPos;
00947          *BitPos += context->slavelist[slave].Ibits - 1;
00948          if (*BitPos > 7)
00949          {
00950             *LogAddr += 1;
00951             *BitPos -= 8;
00952          }
00953          FMMUsize = *LogAddr - etohl(context->slavelist[slave].FMMU[FMMUc].LogStart) + 1;
00954          context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
00955          context->slavelist[slave].FMMU[FMMUc].LogEndbit = *BitPos;
00956          *BitPos += 1;
00957          if (*BitPos > 7)
00958          {
00959             *LogAddr += 1;
00960             *BitPos -= 8;
00961          }
00962       }
00963       /* byte oriented slave */
00964       else
00965       {
00966          if (*BitPos)
00967          {
00968             *LogAddr += 1;
00969             *BitPos = 0;
00970          }
00971          context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(*LogAddr);
00972          context->slavelist[slave].FMMU[FMMUc].LogStartbit = *BitPos;
00973          *BitPos = 7;
00974          FMMUsize = ByteCount;
00975          if ((FMMUsize + FMMUdone)> (int)context->slavelist[slave].Ibytes)
00976          {
00977             FMMUsize = context->slavelist[slave].Ibytes - FMMUdone;
00978          }
00979          *LogAddr += FMMUsize;
00980          context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
00981          context->slavelist[slave].FMMU[FMMUc].LogEndbit = *BitPos;
00982          *BitPos = 0;
00983       }
00984       FMMUdone += FMMUsize;
00985       if (context->slavelist[slave].FMMU[FMMUc].LogLength)
00986       {
00987          context->slavelist[slave].FMMU[FMMUc].PhysStartBit = 0;
00988          context->slavelist[slave].FMMU[FMMUc].FMMUtype = 1;
00989          context->slavelist[slave].FMMU[FMMUc].FMMUactive = 1;
00990          /* program FMMU for input */
00991          ecx_FPWR(context->port, configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc),
00992             sizeof(ec_fmmut), &(context->slavelist[slave].FMMU[FMMUc]), EC_TIMEOUTRET3);
00993          /* add one for an input FMMU */
00994          context->grouplist[group].inputsWKC++;
00995       }
00996       if (!context->slavelist[slave].inputs)
00997       {
00998          if (group)
00999          {
01000             context->slavelist[slave].inputs =
01001                (uint8 *)(pIOmap) + 
01002                etohl(context->slavelist[slave].FMMU[FMMUc].LogStart) - 
01003                context->grouplist[group].logstartaddr;
01004          }
01005          else
01006          {
01007             context->slavelist[slave].inputs =
01008                (uint8 *)(pIOmap) +
01009                etohl(context->slavelist[slave].FMMU[FMMUc].LogStart);
01010          }
01011          context->slavelist[slave].Istartbit =
01012             context->slavelist[slave].FMMU[FMMUc].LogStartbit;
01013          EC_PRINT("    Inputs %p startbit %d\n",
01014             context->slavelist[slave].inputs,
01015             context->slavelist[slave].Istartbit);
01016       }
01017       FMMUc++;
01018    }
01019    context->slavelist[slave].FMMUunused = FMMUc;
01020 }
01021 
01022 static void ecx_config_create_output_mappings(ecx_contextt *context, void *pIOmap, 
01023    uint8 group, int16 slave, uint32 * LogAddr, uint8 * BitPos)
01024 {
01025    int BitCount = 0;
01026    int ByteCount = 0;
01027    int FMMUsize = 0;
01028    int FMMUdone = 0;
01029    uint8 SMc = 0;
01030    uint16 EndAddr;
01031    uint16 SMlength;
01032    uint16 configadr;
01033    uint8 FMMUc;
01034 
01035    EC_PRINT("  OUTPUT MAPPING\n");
01036 
01037    FMMUc = context->slavelist[slave].FMMUunused;
01038    configadr = context->slavelist[slave].configadr;
01039 
01040    /* search for SM that contribute to the output mapping */
01041    while ((SMc < (EC_MAXSM - 1)) && (FMMUdone < ((context->slavelist[slave].Obits + 7) / 8)))
01042    {
01043       EC_PRINT("    FMMU %d\n", FMMUc);
01044       while ((SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 3))
01045       {
01046          SMc++;
01047       }
01048       EC_PRINT("      SM%d\n", SMc);
01049       context->slavelist[slave].FMMU[FMMUc].PhysStart =
01050          context->slavelist[slave].SM[SMc].StartAddr;
01051       SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength);
01052       ByteCount += SMlength;
01053       BitCount += SMlength * 8;
01054       EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength;
01055       while ((BitCount < context->slavelist[slave].Obits) && (SMc < (EC_MAXSM - 1))) /* more SM for output */
01056       {
01057          SMc++;
01058          while ((SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 3))
01059          {
01060             SMc++;
01061          }
01062          /* if addresses from more SM connect use one FMMU otherwise break up in multiple FMMU */
01063          if (etohs(context->slavelist[slave].SM[SMc].StartAddr) > EndAddr)
01064          {
01065             break;
01066          }
01067          EC_PRINT("      SM%d\n", SMc);
01068          SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength);
01069          ByteCount += SMlength;
01070          BitCount += SMlength * 8;
01071          EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength;
01072       }
01073 
01074       /* bit oriented slave */
01075       if (!context->slavelist[slave].Obytes)
01076       {
01077          context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(*LogAddr);
01078          context->slavelist[slave].FMMU[FMMUc].LogStartbit = *BitPos;
01079          *BitPos += context->slavelist[slave].Obits - 1;
01080          if (*BitPos > 7)
01081          {
01082             *LogAddr += 1;
01083             *BitPos -= 8;
01084          }
01085          FMMUsize = *LogAddr - etohl(context->slavelist[slave].FMMU[FMMUc].LogStart) + 1;
01086          context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
01087          context->slavelist[slave].FMMU[FMMUc].LogEndbit = *BitPos;
01088          *BitPos += 1;
01089          if (*BitPos > 7)
01090          {
01091             *LogAddr += 1;
01092             *BitPos -= 8;
01093          }
01094       }
01095       /* byte oriented slave */
01096       else
01097       {
01098          if (*BitPos)
01099          {
01100             *LogAddr += 1;
01101             *BitPos = 0;
01102          }
01103          context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(*LogAddr);
01104          context->slavelist[slave].FMMU[FMMUc].LogStartbit = *BitPos;
01105          *BitPos = 7;
01106          FMMUsize = ByteCount;
01107          if ((FMMUsize + FMMUdone)> (int)context->slavelist[slave].Obytes)
01108          {
01109             FMMUsize = context->slavelist[slave].Obytes - FMMUdone;
01110          }
01111          *LogAddr += FMMUsize;
01112          context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
01113          context->slavelist[slave].FMMU[FMMUc].LogEndbit = *BitPos;
01114          *BitPos = 0;
01115       }
01116       FMMUdone += FMMUsize;
01117       context->slavelist[slave].FMMU[FMMUc].PhysStartBit = 0;
01118       context->slavelist[slave].FMMU[FMMUc].FMMUtype = 2;
01119       context->slavelist[slave].FMMU[FMMUc].FMMUactive = 1;
01120       /* program FMMU for output */
01121       ecx_FPWR(context->port, configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc),
01122          sizeof(ec_fmmut), &(context->slavelist[slave].FMMU[FMMUc]), EC_TIMEOUTRET3);
01123       context->grouplist[group].outputsWKC++;
01124       if (!context->slavelist[slave].outputs)
01125       {
01126          if (group)
01127          {
01128             context->slavelist[slave].outputs =
01129                (uint8 *)(pIOmap) + 
01130                etohl(context->slavelist[slave].FMMU[FMMUc].LogStart) - 
01131                context->grouplist[group].logstartaddr;
01132          }
01133          else
01134          {
01135             context->slavelist[slave].outputs =
01136                (uint8 *)(pIOmap) + 
01137                etohl(context->slavelist[slave].FMMU[FMMUc].LogStart);
01138          }
01139          context->slavelist[slave].Ostartbit =
01140             context->slavelist[slave].FMMU[FMMUc].LogStartbit;
01141          EC_PRINT("    slave %d Outputs %p startbit %d\n",
01142             slave,
01143             context->slavelist[slave].outputs,
01144             context->slavelist[slave].Ostartbit);
01145       }
01146       FMMUc++;
01147    }
01148    context->slavelist[slave].FMMUunused = FMMUc;
01149 }
01150 
01151 /** Map all PDOs in one group of slaves to IOmap with Outputs/Inputs
01152 * in sequential order (legacy SOEM way).
01153 *
01154  *
01155  * @param[in]  context    = context struct
01156  * @param[out] pIOmap     = pointer to IOmap
01157  * @param[in]  group      = group to map, 0 = all groups
01158  * @return IOmap size
01159  */
01160 int ecx_config_map_group(ecx_contextt *context, void *pIOmap, uint8 group)
01161 {
01162    uint16 slave, configadr;
01163    uint8 BitPos;
01164    uint32 LogAddr = 0;
01165    uint32 oLogAddr = 0;
01166    uint32 diff;
01167    uint16 currentsegment = 0;
01168    uint32 segmentsize = 0;
01169 
01170    if ((*(context->slavecount) > 0) && (group < context->maxgroup))
01171    {
01172       EC_PRINT("ec_config_map_group IOmap:%p group:%d\n", pIOmap, group);
01173       LogAddr = context->grouplist[group].logstartaddr;
01174       oLogAddr = LogAddr;
01175       BitPos = 0;
01176       context->grouplist[group].nsegments = 0;
01177       context->grouplist[group].outputsWKC = 0;
01178       context->grouplist[group].inputsWKC = 0;
01179 
01180       /* Find mappings and program syncmanagers */
01181       ecx_config_find_mappings(context, group);
01182 
01183       /* do output mapping of slave and program FMMUs */
01184       for (slave = 1; slave <= *(context->slavecount); slave++)
01185       {
01186          configadr = context->slavelist[slave].configadr;
01187 
01188          if (!group || (group == context->slavelist[slave].group))
01189          {
01190             /* create output mapping */
01191             if (context->slavelist[slave].Obits)
01192             {
01193                ecx_config_create_output_mappings (context, pIOmap, group, slave, &LogAddr, &BitPos);
01194                diff = LogAddr - oLogAddr;
01195                oLogAddr = LogAddr;
01196                if ((segmentsize + diff) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM))
01197                {
01198                   context->grouplist[group].IOsegment[currentsegment] = segmentsize;
01199                   if (currentsegment < (EC_MAXIOSEGMENTS - 1))
01200                   {
01201                      currentsegment++;
01202                      segmentsize = diff;
01203                   }
01204                }
01205                else
01206                {
01207                   segmentsize += diff;
01208                }
01209             }
01210          }
01211       }
01212       if (BitPos)
01213       {
01214          LogAddr++;
01215          oLogAddr = LogAddr;
01216          BitPos = 0;
01217          if ((segmentsize + 1) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM))
01218          {
01219             context->grouplist[group].IOsegment[currentsegment] = segmentsize;
01220             if (currentsegment < (EC_MAXIOSEGMENTS - 1))
01221             {
01222                currentsegment++;
01223                segmentsize = 1;
01224             }
01225          }
01226          else
01227          {
01228             segmentsize += 1;
01229          }
01230       }
01231       context->grouplist[group].outputs = pIOmap;
01232       context->grouplist[group].Obytes = LogAddr - context->grouplist[group].logstartaddr;
01233       context->grouplist[group].nsegments = currentsegment + 1;
01234       context->grouplist[group].Isegment = currentsegment;
01235       context->grouplist[group].Ioffset = segmentsize;
01236       if (!group)
01237       {
01238          context->slavelist[0].outputs = pIOmap;
01239          context->slavelist[0].Obytes = LogAddr - 
01240             context->grouplist[group].logstartaddr; /* store output bytes in master record */
01241       }
01242 
01243       /* do input mapping of slave and program FMMUs */
01244       for (slave = 1; slave <= *(context->slavecount); slave++)
01245       {
01246          configadr = context->slavelist[slave].configadr;
01247          if (!group || (group == context->slavelist[slave].group))
01248          {
01249             /* create input mapping */
01250             if (context->slavelist[slave].Ibits)
01251             {
01252  
01253                ecx_config_create_input_mappings(context, pIOmap, group, slave, &LogAddr, &BitPos);
01254                diff = LogAddr - oLogAddr;
01255                oLogAddr = LogAddr;
01256                if ((segmentsize + diff) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM))
01257                {
01258                   context->grouplist[group].IOsegment[currentsegment] = segmentsize;
01259                   if (currentsegment < (EC_MAXIOSEGMENTS - 1))
01260                   {
01261                      currentsegment++;
01262                      segmentsize = diff;
01263                   }
01264                }
01265                else
01266                {
01267                   segmentsize += diff;
01268                }
01269             }
01270 
01271             ecx_eeprom2pdi(context, slave); /* set Eeprom control to PDI */
01272             ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_SAFE_OP) , EC_TIMEOUTRET3); /* set safeop status */
01273 
01274             if (context->slavelist[slave].blockLRW)
01275             {
01276                context->grouplist[group].blockLRW++;
01277             }
01278             context->grouplist[group].Ebuscurrent += context->slavelist[slave].Ebuscurrent;
01279          }
01280       }
01281       if (BitPos)
01282       {
01283          LogAddr++;
01284          oLogAddr = LogAddr;
01285          BitPos = 0;
01286          if ((segmentsize + 1) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM))
01287          {
01288             context->grouplist[group].IOsegment[currentsegment] = segmentsize;
01289             if (currentsegment < (EC_MAXIOSEGMENTS - 1))
01290             {
01291                currentsegment++;
01292                segmentsize = 1;
01293             }
01294          }
01295          else
01296          {
01297             segmentsize += 1;
01298          }
01299       }
01300       context->grouplist[group].IOsegment[currentsegment] = segmentsize;
01301       context->grouplist[group].nsegments = currentsegment + 1;
01302       context->grouplist[group].inputs = (uint8 *)(pIOmap) + context->grouplist[group].Obytes;
01303       context->grouplist[group].Ibytes = LogAddr - 
01304          context->grouplist[group].logstartaddr - 
01305          context->grouplist[group].Obytes;
01306       if (!group)
01307       {
01308          context->slavelist[0].inputs = (uint8 *)(pIOmap) + context->slavelist[0].Obytes;
01309          context->slavelist[0].Ibytes = LogAddr - 
01310             context->grouplist[group].logstartaddr - 
01311             context->slavelist[0].Obytes; /* store input bytes in master record */
01312       }
01313 
01314       EC_PRINT("IOmapSize %d\n", LogAddr - context->grouplist[group].logstartaddr);
01315 
01316       return (LogAddr - context->grouplist[group].logstartaddr);
01317    }
01318 
01319    return 0;
01320 }
01321 
01322 /** Map all PDOs in one group of slaves to IOmap with Outputs/Inputs
01323  * overlapping. NOTE: Must use this for TI ESC when using LRW.
01324  *
01325  * @param[in]  context    = context struct
01326  * @param[out] pIOmap     = pointer to IOmap
01327  * @param[in]  group      = group to map, 0 = all groups
01328  * @return IOmap size
01329  */
01330 int ecx_config_overlap_map_group(ecx_contextt *context, void *pIOmap, uint8 group)
01331 {
01332    uint16 slave, configadr;
01333    uint8 BitPos;
01334    uint32 mLogAddr = 0;
01335    uint32 siLogAddr = 0;
01336    uint32 soLogAddr = 0;
01337    uint32 tempLogAddr;
01338    uint32 diff;
01339    uint16 currentsegment = 0;
01340    uint32 segmentsize = 0;
01341 
01342    if ((*(context->slavecount) > 0) && (group < context->maxgroup))
01343    {
01344       EC_PRINT("ec_config_map_group IOmap:%p group:%d\n", pIOmap, group);
01345       mLogAddr = context->grouplist[group].logstartaddr;
01346       siLogAddr = mLogAddr;
01347       soLogAddr = mLogAddr;
01348       BitPos = 0;
01349       context->grouplist[group].nsegments = 0;
01350       context->grouplist[group].outputsWKC = 0;
01351       context->grouplist[group].inputsWKC = 0;
01352 
01353       /* Find mappings and program syncmanagers */
01354       ecx_config_find_mappings(context, group);
01355       
01356       /* do IO mapping of slave and program FMMUs */
01357       for (slave = 1; slave <= *(context->slavecount); slave++)
01358       {
01359          configadr = context->slavelist[slave].configadr;
01360          siLogAddr = soLogAddr = mLogAddr;
01361 
01362          if (!group || (group == context->slavelist[slave].group))
01363          {
01364             /* create output mapping */
01365             if (context->slavelist[slave].Obits)
01366             {
01367                
01368                ecx_config_create_output_mappings(context, pIOmap, group, 
01369                   slave, &soLogAddr, &BitPos);
01370                if (BitPos)
01371                {
01372                   soLogAddr++;
01373                   BitPos = 0;
01374                }
01375             }
01376 
01377             /* create input mapping */
01378             if (context->slavelist[slave].Ibits)
01379             {
01380                ecx_config_create_input_mappings(context, pIOmap, group, 
01381                   slave, &siLogAddr, &BitPos);
01382                if (BitPos)
01383                {
01384                   siLogAddr++;
01385                   BitPos = 0;
01386                }
01387             }
01388 
01389             tempLogAddr = (siLogAddr > soLogAddr) ?  siLogAddr : soLogAddr;
01390             diff = tempLogAddr - mLogAddr;
01391             mLogAddr = tempLogAddr;
01392 
01393             if ((segmentsize + diff) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM))
01394             {
01395                context->grouplist[group].IOsegment[currentsegment] = segmentsize;
01396                if (currentsegment < (EC_MAXIOSEGMENTS - 1))
01397                {
01398                   currentsegment++;
01399                   segmentsize = diff;
01400                }
01401             }
01402             else
01403             {
01404                segmentsize += diff;
01405             }
01406 
01407             ecx_eeprom2pdi(context, slave); /* set Eeprom control to PDI */
01408             ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_SAFE_OP), EC_TIMEOUTRET3); /* set safeop status */
01409 
01410             if (context->slavelist[slave].blockLRW)
01411             {
01412                context->grouplist[group].blockLRW++;
01413             }
01414             context->grouplist[group].Ebuscurrent += context->slavelist[slave].Ebuscurrent;
01415 
01416          }
01417       }
01418 
01419       context->grouplist[group].IOsegment[currentsegment] = segmentsize;
01420       context->grouplist[group].nsegments = currentsegment + 1;
01421       context->grouplist[group].Isegment = 0;
01422       context->grouplist[group].Ioffset = 0;
01423 
01424       context->grouplist[group].Obytes = soLogAddr - context->grouplist[group].logstartaddr;
01425       context->grouplist[group].Ibytes = siLogAddr - context->grouplist[group].logstartaddr;
01426       context->grouplist[group].outputs = pIOmap;
01427       context->grouplist[group].inputs = (uint8 *)pIOmap + context->grouplist[group].Obytes;
01428 
01429       /* Move calculated inputs with OBytes offset*/
01430       for (slave = 1; slave <= *(context->slavecount); slave++)
01431       {
01432          context->slavelist[slave].inputs += context->grouplist[group].Obytes;
01433       }
01434 
01435       if (!group)
01436       {
01437          /* store output bytes in master record */
01438          context->slavelist[0].outputs = pIOmap;
01439          context->slavelist[0].Obytes = soLogAddr - context->grouplist[group].logstartaddr; 
01440          context->slavelist[0].inputs = (uint8 *)pIOmap + context->slavelist[0].Obytes;
01441          context->slavelist[0].Ibytes = siLogAddr - context->grouplist[group].logstartaddr;
01442       }
01443 
01444       EC_PRINT("IOmapSize %d\n", context->grouplist[group].Obytes + context->grouplist[group].Ibytes);
01445 
01446       return (context->grouplist[group].Obytes + context->grouplist[group].Ibytes);
01447    }
01448 
01449    return 0;
01450 }
01451 
01452 
01453 /** Recover slave.
01454  *
01455  * @param[in] context = context struct
01456  * @param[in] slave   = slave to recover
01457  * @param[in] timeout = local timeout f.e. EC_TIMEOUTRET3
01458  * @return >0 if successful
01459  */
01460 int ecx_recover_slave(ecx_contextt *context, uint16 slave, int timeout)
01461 {
01462    int rval;
01463    int wkc;
01464    uint16 ADPh, configadr, readadr;
01465 
01466    rval = 0;
01467    configadr = context->slavelist[slave].configadr;
01468    ADPh = (uint16)(1 - slave);
01469    /* check if we found another slave than the requested */
01470    readadr = 0xfffe;
01471    wkc = ecx_APRD(context->port, ADPh, ECT_REG_STADR, sizeof(readadr), &readadr, timeout);
01472    /* correct slave found, finished */
01473    if(readadr == configadr)
01474    {
01475        return 1;
01476    }
01477    /* only try if no config address*/
01478    if( (wkc > 0) && (readadr == 0))
01479    {
01480       /* clear possible slaves at EC_TEMPNODE */
01481       ecx_FPWRw(context->port, EC_TEMPNODE, ECT_REG_STADR, htoes(0) , 0);
01482       /* set temporary node address of slave */
01483       if(ecx_APWRw(context->port, ADPh, ECT_REG_STADR, htoes(EC_TEMPNODE) , timeout) <= 0)
01484       {
01485          ecx_FPWRw(context->port, EC_TEMPNODE, ECT_REG_STADR, htoes(0) , 0);
01486          return 0; /* slave fails to respond */
01487       }
01488 
01489       context->slavelist[slave].configadr = EC_TEMPNODE; /* temporary config address */
01490       ecx_eeprom2master(context, slave); /* set Eeprom control to master */
01491 
01492       /* check if slave is the same as configured before */
01493       if ((ecx_FPRDw(context->port, EC_TEMPNODE, ECT_REG_ALIAS, timeout) ==
01494              htoes(context->slavelist[slave].aliasadr)) &&
01495           (ecx_readeeprom(context, slave, ECT_SII_ID, EC_TIMEOUTEEP) ==
01496              htoel(context->slavelist[slave].eep_id)) &&
01497           (ecx_readeeprom(context, slave, ECT_SII_MANUF, EC_TIMEOUTEEP) ==
01498              htoel(context->slavelist[slave].eep_man)) &&
01499           (ecx_readeeprom(context, slave, ECT_SII_REV, EC_TIMEOUTEEP) ==
01500              htoel(context->slavelist[slave].eep_rev)))
01501       {
01502          rval = ecx_FPWRw(context->port, EC_TEMPNODE, ECT_REG_STADR, htoes(configadr) , timeout);
01503          context->slavelist[slave].configadr = configadr;
01504       }
01505       else
01506       {
01507          /* slave is not the expected one, remove config address*/
01508          ecx_FPWRw(context->port, EC_TEMPNODE, ECT_REG_STADR, htoes(0) , timeout);
01509          context->slavelist[slave].configadr = configadr;
01510       }
01511    }
01512 
01513    return rval;
01514 }
01515 
01516 /** Reconfigure slave.
01517  *
01518  * @param[in] context = context struct
01519  * @param[in] slave   = slave to reconfigure
01520  * @param[in] timeout = local timeout f.e. EC_TIMEOUTRET3
01521  * @return Slave state
01522  */
01523 int ecx_reconfig_slave(ecx_contextt *context, uint16 slave, int timeout)
01524 {
01525    int state, nSM, FMMUc;
01526    uint16 configadr;
01527 
01528    configadr = context->slavelist[slave].configadr;
01529    if (ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_INIT) , timeout) <= 0)
01530    {
01531       return 0;
01532    }
01533    state = 0;
01534    ecx_eeprom2pdi(context, slave); /* set Eeprom control to PDI */
01535    /* check state change init */
01536    state = ecx_statecheck(context, slave, EC_STATE_INIT, EC_TIMEOUTSTATE);
01537    if(state == EC_STATE_INIT)
01538    {
01539       /* program all enabled SM */
01540       for( nSM = 0 ; nSM < EC_MAXSM ; nSM++ )
01541       {
01542          if (context->slavelist[slave].SM[nSM].StartAddr)
01543          {
01544             ecx_FPWR(context->port, configadr, (uint16)(ECT_REG_SM0 + (nSM * sizeof(ec_smt))),
01545                sizeof(ec_smt), &context->slavelist[slave].SM[nSM], timeout);
01546          }
01547       }
01548       ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_PRE_OP) , timeout);
01549       state = ecx_statecheck(context, slave, EC_STATE_PRE_OP, EC_TIMEOUTSTATE); /* check state change pre-op */
01550       if( state == EC_STATE_PRE_OP)
01551       {
01552          /* execute special slave configuration hook Pre-Op to Safe-OP */
01553          if(context->slavelist[slave].PO2SOconfig) /* only if registered */
01554          {
01555             context->slavelist[slave].PO2SOconfig(slave);
01556          }
01557          ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_SAFE_OP) , timeout); /* set safeop status */
01558          state = ecx_statecheck(context, slave, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); /* check state change safe-op */
01559          /* program configured FMMU */
01560          for( FMMUc = 0 ; FMMUc < context->slavelist[slave].FMMUunused ; FMMUc++ )
01561          {
01562             ecx_FPWR(context->port, configadr, (uint16)(ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc)),
01563                sizeof(ec_fmmut), &context->slavelist[slave].FMMU[FMMUc], timeout);
01564          }
01565       }
01566    }
01567 
01568    return state;
01569 }
01570 
01571 #ifdef EC_VER1
01572 /** Enumerate and init all slaves.
01573  *
01574  * @param[in] usetable     = TRUE when using configtable to init slaves, FALSE otherwise
01575  * @return Workcounter of slave discover datagram = number of slaves found
01576  * @see ecx_config_init
01577  */
01578 int ec_config_init(uint8 usetable)
01579 {
01580    return ecx_config_init(&ecx_context, usetable);
01581 }
01582 
01583 /** Map all PDOs in one group of slaves to IOmap with Outputs/Inputs
01584  * in sequential order (legacy SOEM way).
01585  *
01586  * @param[out] pIOmap     = pointer to IOmap
01587  * @param[in]  group      = group to map, 0 = all groups
01588  * @return IOmap size
01589  * @see ecx_config_map_group
01590  */
01591 int ec_config_map_group(void *pIOmap, uint8 group)
01592 {
01593    return ecx_config_map_group(&ecx_context, pIOmap, group);
01594 }
01595 
01596 /** Map all PDOs in one group of slaves to IOmap with Outputs/Inputs
01597 * overlapping. NOTE: Must use this for TI ESC when using LRW.
01598 *
01599 * @param[out] pIOmap     = pointer to IOmap
01600 * @param[in]  group      = group to map, 0 = all groups
01601 * @return IOmap size
01602 * @see ecx_config_overlap_map_group
01603 */
01604 int ec_config_overlap_map_group(void *pIOmap, uint8 group)
01605 {
01606    return ecx_config_overlap_map_group(&ecx_context, pIOmap, group);
01607 }
01608 
01609 /** Map all PDOs from slaves to IOmap with Outputs/Inputs
01610  * in sequential order (legacy SOEM way).
01611  *
01612  * @param[out] pIOmap     = pointer to IOmap
01613  * @return IOmap size
01614  */
01615 int ec_config_map(void *pIOmap)
01616 {
01617    return ec_config_map_group(pIOmap, 0);
01618 }
01619 
01620 /** Map all PDOs from slaves to IOmap with Outputs/Inputs
01621 * overlapping. NOTE: Must use this for TI ESC when using LRW.
01622 *
01623 * @param[out] pIOmap     = pointer to IOmap
01624 * @return IOmap size
01625 */
01626 int ec_config_overlap_map(void *pIOmap)
01627 {
01628    return ec_config_overlap_map_group(pIOmap, 0);
01629 }
01630 
01631 /** Enumerate / map and init all slaves.
01632  *
01633  * @param[in] usetable    = TRUE when using configtable to init slaves, FALSE otherwise
01634  * @param[out] pIOmap     = pointer to IOmap
01635  * @return Workcounter of slave discover datagram = number of slaves found
01636  */
01637 int ec_config(uint8 usetable, void *pIOmap)
01638 {
01639    int wkc;
01640    wkc = ec_config_init(usetable);
01641    if (wkc)
01642    {
01643       ec_config_map(pIOmap);
01644    }
01645    return wkc;
01646 }
01647 
01648 /** Enumerate / map and init all slaves.
01649 *
01650 * @param[in] usetable    = TRUE when using configtable to init slaves, FALSE otherwise
01651 * @param[out] pIOmap     = pointer to IOmap
01652 * @return Workcounter of slave discover datagram = number of slaves found
01653 */
01654 int ec_config_overlap(uint8 usetable, void *pIOmap)
01655 {
01656    int wkc;
01657    wkc = ec_config_init(usetable);
01658    if (wkc)
01659    {
01660       ec_config_overlap_map(pIOmap);
01661    }
01662    return wkc;
01663 }
01664 
01665 /** Recover slave.
01666  *
01667  * @param[in] slave   = slave to recover
01668  * @param[in] timeout = local timeout f.e. EC_TIMEOUTRET3
01669  * @return >0 if successful
01670  * @see ecx_recover_slave
01671  */
01672 int ec_recover_slave(uint16 slave, int timeout)
01673 {
01674    return ecx_recover_slave(&ecx_context, slave, timeout);
01675 }
01676 
01677 /** Reconfigure slave.
01678  *
01679  * @param[in] slave   = slave to reconfigure
01680  * @param[in] timeout = local timeout f.e. EC_TIMEOUTRET3
01681  * @return Slave state
01682  * @see ecx_reconfig_slave
01683  */
01684 int ec_reconfig_slave(uint16 slave, int timeout)
01685 {
01686    return ecx_reconfig_slave(&ecx_context, slave, timeout);
01687 }
01688 #endif