예제 #1
0
파일: esc_hw.c 프로젝트: hefloryd/SOES
/** PDI ISR handler
 *
 * @param[in]   arg     = NOT USED
 */
static void ecat_isr (void * arg)
{

   ESC_read (ESCREG_LOCALTIME, (void *) &ESCvar.Time, sizeof (ESCvar.Time));
   ESCvar.Time = etohl (ESCvar.Time);
   CC_ATOMIC_SET(ESCvar.ALevent, etohl(ecat0->AL_EVENT_REQ));

   if(ESCvar.ALevent & ESCREG_ALEVENT_SM2)
   {
      if(ESCvar.dcsync == 0)
      {
         DIG_process(DIG_PROCESS_OUTPUTS_FLAG | DIG_PROCESS_APP_HOOK_FLAG |
               DIG_PROCESS_INPUTS_FLAG);
      }
      else
      {
         DIG_process(DIG_PROCESS_OUTPUTS_FLAG);
      }
   }

#if 1
   if(ESCvar.ALevent & (ESCREG_ALEVENT_CONTROL | ESCREG_ALEVENT_SMCHANGE
         | ESCREG_ALEVENT_SM0 | ESCREG_ALEVENT_SM1 | ESCREG_ALEVENT_EEP))
   {
      /* Mask interrupts while servicing them */
      ecat0->AL_EVENT_MASK &= ~(ESCREG_ALEVENT_CONTROL | ESCREG_ALEVENT_SMCHANGE
            | ESCREG_ALEVENT_SM0 | ESCREG_ALEVENT_SM1 | ESCREG_ALEVENT_EEP);

      extern flags_t * ecat_events;
      flags_set(ecat_events, EVENT_ISR);
      //sem_signal(ecat_isr_sem);
   }
#endif
}
예제 #2
0
void FOE_write()
{
    _FOE *foembx;
    uint16_t data_len;
    uint32_t password;
    int16_t res;

    if(ESCvar.foestate != FOE_READY)
    {
        FOE_abort(FOE_ERR_ILLEGAL);
        return;
    }

    FOE_init();
    foembx = (_FOE*)&MBX[0];
    data_len = etohs(foembx->mbxheader.length) - FOEHSIZE;
    password = etohl(foembx->foeheader.x.password);

    /* Get an address we can write the file to, if possible. */
    res = FOE_fopen(foembx->y.filename, data_len, password, FOE_OP_WRQ);
    if(res==0)
    {
        res = FOE_send_ack();
        if(res)
            FOE_abort(res);
        else
            ESCvar.foestate = FOE_WAIT_FOR_DATA;
    }
    else
        FOE_abort(res);
}
예제 #3
0
void FOE_read()
{
    _FOE *foembx;
    uint16_t data_len;
    uint32_t password;
    uint16_t res;

    if(ESCvar.foestate != FOE_READY)
    {
        FOE_abort(FOE_ERR_ILLEGAL);
        return;
    }

    FOE_init();
    foembx = (_FOE*)&MBX[0];
    //Get the length of the file name in octets.
    data_len = etohs(foembx->mbxheader.length) - FOEHSIZE;
    password = etohl(foembx->foeheader.x.password);

    res = FOE_fopen(foembx->y.filename, data_len, password, FOE_OP_RRQ);
    if(res==0)
    {
        ESCvar.foepacket=1;
        /* Attempt to send the packet */
        res = FOE_send_data_packet();
        if(res <= FOE_DATA_SIZE)
        {
            ESCvar.foestate = FOE_WAIT_FOR_ACK;
        }
        else
            FOE_abort(res);
    }
    else
        FOE_abort(res);
}
예제 #4
0
파일: slave.c 프로젝트: hefloryd/SOES
/**
 * Polling function. It should be called periodically for an application 
 * when only SM2/DC interrupt is active.
 * Read and handle events for the EtherCAT state, status, mailbox and eeprom.
 */
void ecat_slv_poll (void)
{
   /* Read local time from ESC*/
   ESC_read (ESCREG_LOCALTIME, (void *) &ESCvar.Time, sizeof (ESCvar.Time));
   ESCvar.Time = etohl (ESCvar.Time);

   /* Check the state machine */
   ESC_state();
   /* Check the SM activation event */
   ESC_sm_act_event();

   /* Check mailboxes */
   if (ESC_mbxprocess())
   {
      ESC_coeprocess();
      ESC_foeprocess();
      ESC_xoeprocess();
   }

   /* Call emulated eeprom handler if set */
   if (ESCvar.esc_hw_eep_handler != NULL)
   {
      (ESCvar.esc_hw_eep_handler)();
   }
}
예제 #5
0
/** EPP periodic task of ESC side EEPROM emulation.
 *
 */
void EEP_process (void)
{
   eep_stat_t stat;

   /* check for eeprom event */
   if ((ESCvar.ALevent & ESCREG_ALEVENT_EEP) == 0) {
     return;
   }

   while (1) {
      /* read eeprom status */
      ESC_read (ESCREG_EECONTSTAT, &stat, sizeof (eep_stat_t));
      stat.contstat.reg = etohs(stat.contstat.reg);
      stat.addr = etohl(stat.addr);

      /* check busy flag, exit if job finished */
      if (!stat.contstat.bits.busy) {
        return;
      }

      /* clear error bits */
      stat.contstat.bits.csumErr = 0;
      stat.contstat.bits.eeLoading = 0;
      stat.contstat.bits.ackErr = 0;
      stat.contstat.bits.wrErr = 0;

      /* process commands */
      switch (stat.contstat.bits.cmdReg) {
         case EEP_CMD_IDLE:
            break;

         case EEP_CMD_READ:
         case EEP_CMD_RELOAD:
            /* handle read request */
            if (EEP_read (stat.addr * sizeof(uint16_t), eep_buf, EEP_READ_SIZE) != 0) {
               stat.contstat.bits.ackErr = 1;
            } else {
               ESC_write (ESCREG_EEDATA, eep_buf, EEP_READ_SIZE);
            }
            break;

         case EEP_CMD_WRITE:
            /* handle write request */
            ESC_read (ESCREG_EEDATA, eep_buf, EEP_WRITE_SIZE);
            if (EEP_write (stat.addr * sizeof(uint16_t), eep_buf, EEP_WRITE_SIZE) != 0) {
               stat.contstat.bits.ackErr = 1;
            }
            break;

         default:
            stat.contstat.bits.ackErr = 1;
      }

      /* acknowledge command */
      stat.contstat.reg = htoes(stat.contstat.reg);
      ESC_write (ESCREG_EECONTSTAT, &stat.contstat.reg, sizeof(uint16_t));
   }
}
예제 #6
0
void FOE_data()
{
    _FOE     *foembx;
    uint32_t packet;
//    uint16_t data_len, ncopied;
    uint16_t data_len;
    int16_t res;

    if(ESCvar.foestate != FOE_WAIT_FOR_DATA)
    {
        FOE_abort(FOE_ERR_ILLEGAL);
        return;
    }

    foembx =(_FOE*)&MBX[0];
    data_len = etohs(foembx->mbxheader.length) - FOEHSIZE;
    packet = etohl(foembx->foeheader.x.packetnumber);
    if(packet != ESCvar.foepacket)
        FOE_abort(FOE_ERR_PACKETNO);
    else if(ESCvar.fposition + data_len > ESCvar.fend)
        FOE_abort(FOE_ERR_DISKFULL);
    else
    {
//        ncopied = FOE_fwrite(foembx->y.data, data_len);
        FOE_fwrite(foembx->y.data, data_len);
        if (foe_mode == FOE_WRITE) res = FOE_send_ack(); else res=0;

        if(data_len == FOE_DATA_SIZE)
        {
            //res = FOE_send_ack();
            if(res) FOE_abort(res);
        }
        else
        {
            FOE_fclose();
            FOE_init();
        }
    }
}
예제 #7
0
/** SOES main loop. Start by initializing the stack software followed by
 * the application loop for cyclic read the EtherCAT state and staus, update
 * of I/O.
 */
void soes (void *arg)
{
   DPRINT ("SOES (Simple Open EtherCAT Slave)\n");

   TXPDOsize = SM3_sml = sizeTXPDO ();
   RXPDOsize = SM2_sml = sizeRXPDO ();

   /* Setup post config hooks */
   static esc_cfg_t config =
   {
      .pre_state_change_hook = NULL,
      .post_state_change_hook = post_state_change_hook
   };
   ESC_config ((esc_cfg_t *)&config);

   ESC_reset();
   ESC_init (spi_name);

   task_delay (tick_from_ms (200));

   /*  wait until ESC is started up */
   while ((ESCvar.DLstatus & 0x0001) == 0)
   {
      ESC_read (ESCREG_DLSTATUS, (void *) &ESCvar.DLstatus,
                sizeof (ESCvar.DLstatus));
      ESCvar.DLstatus = etohs (ESCvar.DLstatus);
   }

   /* Pre FoE to set up Application information */
   bootstrap_foe_init ();
   /* Init FoE */
   FOE_init();

   /* reset ESC to init state */
   ESC_ALstatus (ESCinit);
   ESC_ALerror (ALERR_NONE);
   ESC_stopmbx ();
   ESC_stopinput ();
   ESC_stopoutput ();

   DPRINT ("Application_loop GO\n");
   /* application run loop */
   while (1)
   {
      /* On init restore PDO mappings to default size */
      if((ESCvar.ALstatus & 0x0f) == ESCinit)
      {
         txpdomap = DEFAULTTXPDOMAP;
         rxpdomap = DEFAULTRXPDOMAP;
         txpdoitems = DEFAULTTXPDOITEMS;
         rxpdoitems = DEFAULTTXPDOITEMS;
      }
      /* Read local time from ESC*/
      ESC_read (ESCREG_LOCALTIME, (void *) &ESCvar.Time, sizeof (ESCvar.Time));
      ESCvar.Time = etohl (ESCvar.Time);

      /* Check the state machine */
      ESC_state ();

      /* If else to two separate execution paths
       * If we're running BOOSTRAP
       *  - MailBox
       *   - FoE
       * Else we're running normal execution
       *  - MailBox
       *   - CoE
       */
      if(local_boot_state)
      {
         if (ESC_mbxprocess ())
         {
            ESC_foeprocess ();
            ESC_xoeprocess ();
         }
         bootstrap_state ();
       }
      else
      {
         if (ESC_mbxprocess ())
         {
            ESC_coeprocess ();
            ESC_xoeprocess ();
         }
         DIG_process ();
      }
   };
}
예제 #8
0
/** Read PDO assign structure */
int si_PDOassign(uint16 slave, uint16 PDOassign, int mapoffset, int bitoffset)
{
    uint16 idxloop, nidx, subidxloop, rdat, idx, subidx;
    uint8 subcnt;
    int wkc, bsize = 0, rdl;
    int32 rdat2;
    uint8 bitlen, obj_subidx;
    uint16 obj_idx;
    int abs_offset, abs_bit;

    rdl = sizeof(rdat); rdat = 0;
    /* read PDO assign subindex 0 ( = number of PDO's) */
    wkc = ec_SDOread(slave, PDOassign, 0x00, FALSE, &rdl, &rdat, EC_TIMEOUTRXM);
    rdat = etohs(rdat);
    /* positive result from slave ? */
    if ((wkc > 0) && (rdat > 0))
    {
        /* number of available sub indexes */
        nidx = rdat;
        bsize = 0;
        /* read all PDO's */
        for (idxloop = 1; idxloop <= nidx; idxloop++)
        {
            rdl = sizeof(rdat); rdat = 0;
            /* read PDO assign */
            wkc = ec_SDOread(slave, PDOassign, (uint8)idxloop, FALSE, &rdl, &rdat, EC_TIMEOUTRXM);
            /* result is index of PDO */
            idx = etohl(rdat);
            if (idx > 0)
            {
                rdl = sizeof(subcnt); subcnt = 0;
                /* read number of subindexes of PDO */
                wkc = ec_SDOread(slave,idx, 0x00, FALSE, &rdl, &subcnt, EC_TIMEOUTRXM);
                subidx = subcnt;
                /* for each subindex */
                for (subidxloop = 1; subidxloop <= subidx; subidxloop++)
                {
                    rdl = sizeof(rdat2); rdat2 = 0;
                    /* read SDO that is mapped in PDO */
                    wkc = ec_SDOread(slave, idx, (uint8)subidxloop, FALSE, &rdl, &rdat2, EC_TIMEOUTRXM);
                    rdat2 = etohl(rdat2);
                    /* extract bitlength of SDO */
                    bitlen = LO_BYTE(rdat2);
                    bsize += bitlen;
                    obj_idx = (uint16)(rdat2 >> 16);
                    obj_subidx = (uint8)((rdat2 >> 8) & 0x000000ff);
                    abs_offset = mapoffset + (bitoffset / 8);
                    abs_bit = bitoffset % 8;
                    ODlist.Slave = slave;
                    ODlist.Index[0] = obj_idx;
                    OElist.Entries = 0;
                    wkc = 0;
                    /* read object entry from dictionary if not a filler (0x0000:0x00) */
                    if(obj_idx || obj_subidx)
                        wkc = ec_readOEsingle(0, obj_subidx, &ODlist, &OElist);
                    printf("  [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen);
                    if((wkc > 0) && OElist.Entries)
                    {
                        printf(" %-12s %s\n", dtype2string(OElist.DataType[obj_subidx]), OElist.Name[obj_subidx]);
                    }
                    else
                        printf("\n");
                    bitoffset += bitlen;
                };
            };
        };
예제 #9
0
/** Map all PDOs in one group of slaves to IOmap.
 *
 * @param[in]  context        = context struct
 * @param[out] pIOmap     = pointer to IOmap   
 * @param[in]  group      = group to map, 0 = all groups   
 * @return IOmap size
 */
int ecx_config_map_group(ecx_contextt *context, void *pIOmap, uint8 group)
{
   uint16 slave, configadr;
   int Isize, Osize, BitCount, ByteCount, FMMUsize, FMMUdone;
   uint16 SMlength, EndAddr;
   uint8 BitPos;
   uint8 SMc, FMMUc;
   uint32 LogAddr = 0;
   uint32 oLogAddr = 0;
   uint32 diff;
   int nSM, rval;
   ec_eepromPDOt eepPDO;
   uint16 currentsegment = 0;
   uint32 segmentsize = 0;

   if ((*(context->slavecount) > 0) && (group < context->maxgroup))
   {   
      EC_PRINT("ec_config_map_group IOmap:%p group:%d\n", pIOmap, group);
      LogAddr = context->grouplist[group].logstartaddr;
      oLogAddr = LogAddr;
      BitPos = 0;
      context->grouplist[group].nsegments = 0;
      context->grouplist[group].outputsWKC = 0;
      context->grouplist[group].inputsWKC = 0;

      /* find output mapping of slave and program FMMU */
      for (slave = 1; slave <= *(context->slavecount); slave++)
      {
         configadr = context->slavelist[slave].configadr;

         ecx_statecheck(context, slave, EC_STATE_PRE_OP, EC_TIMEOUTSTATE); /* check state change pre-op */

         EC_PRINT(" >Slave %d, configadr %x, state %2.2x\n",
                  slave, context->slavelist[slave].configadr, context->slavelist[slave].state);

         /* execute special slave configuration hook Pre-Op to Safe-OP */
         if(context->slavelist[slave].PO2SOconfig) /* only if registered */
         {
            context->slavelist[slave].PO2SOconfig(slave);         
         }
         if (!group || (group == context->slavelist[slave].group))
         {   
         
            /* if slave not found in configlist find IO mapping in slave self */
            if (!context->slavelist[slave].configindex)
            {
               Isize = 0;
               Osize = 0;
               if (context->slavelist[slave].mbx_proto & ECT_MBXPROT_COE) /* has CoE */
               {
                  rval = 0;
                  if (context->slavelist[slave].CoEdetails & ECT_COEDET_SDOCA) /* has Complete Access */
                     /* read PDO mapping via CoE and use Complete Access */
                  {
                     rval = ecx_readPDOmapCA(context, slave, &Osize, &Isize);
                  }
                  if (!rval) /* CA not available or not succeeded */
                  {
                     /* read PDO mapping via CoE */
                     rval = ecx_readPDOmap(context, slave, &Osize, &Isize);
                  }
                  EC_PRINT("  CoE Osize:%d Isize:%d\n", Osize, Isize);
               }
               if ((!Isize && !Osize) && (context->slavelist[slave].mbx_proto & ECT_MBXPROT_SOE)) /* has SoE */
               {
                  /* read AT / MDT mapping via SoE */
                  rval = ecx_readIDNmap(context, slave, &Osize, &Isize);
                  context->slavelist[slave].SM[2].SMlength = htoes((Osize + 7) / 8);
                  context->slavelist[slave].SM[3].SMlength = htoes((Isize + 7) / 8);
                  EC_PRINT("  SoE Osize:%d Isize:%d\n", Osize, Isize);
               }
               if (!Isize && !Osize) /* find PDO mapping by SII */
               {
                  memset(&eepPDO, 0, sizeof(eepPDO));
                  Isize = (int)ecx_siiPDO(context, slave, &eepPDO, 0);
                  EC_PRINT("  SII Isize:%d\n", Isize);               
                  for( nSM=0 ; nSM < EC_MAXSM ; nSM++ )
                  {   
                     if (eepPDO.SMbitsize[nSM] > 0)
                     {   
                        context->slavelist[slave].SM[nSM].SMlength =  htoes((eepPDO.SMbitsize[nSM] + 7) / 8);
                        context->slavelist[slave].SMtype[nSM] = 4;
                        EC_PRINT("    SM%d length %d\n", nSM, eepPDO.SMbitsize[nSM]);
                     }   
                  }   
                  Osize = (int)ecx_siiPDO(context, slave, &eepPDO, 1);
                  EC_PRINT("  SII Osize:%d\n", Osize);               
                  for( nSM=0 ; nSM < EC_MAXSM ; nSM++ )
                  {   
                     if (eepPDO.SMbitsize[nSM] > 0)
                     {   
                        context->slavelist[slave].SM[nSM].SMlength =  htoes((eepPDO.SMbitsize[nSM] + 7) / 8);
                        context->slavelist[slave].SMtype[nSM] = 3;
                        EC_PRINT("    SM%d length %d\n", nSM, eepPDO.SMbitsize[nSM]);
                     }   
                  }   
               }
               context->slavelist[slave].Obits = Osize;
               context->slavelist[slave].Ibits = Isize;
               EC_PRINT("     ISIZE:%d %d OSIZE:%d\n", 
                  context->slavelist[slave].Ibits, Isize,context->slavelist[slave].Obits);    
            }

            EC_PRINT("  SM programming\n");  
            if (!context->slavelist[slave].mbx_l && context->slavelist[slave].SM[0].StartAddr)
            {
               ecx_FPWR(context->port, configadr, ECT_REG_SM0, 
                  sizeof(ec_smt), &(context->slavelist[slave].SM[0]), EC_TIMEOUTRET3);
               EC_PRINT("    SM0 Type:%d StartAddr:%4.4x Flags:%8.8x\n", 
                   context->slavelist[slave].SMtype[0], 
                   context->slavelist[slave].SM[0].StartAddr, 
                   context->slavelist[slave].SM[0].SMflags);   
            }
            if (!context->slavelist[slave].mbx_l && context->slavelist[slave].SM[1].StartAddr)
            {
               ecx_FPWR(context->port, configadr, ECT_REG_SM1, 
                  sizeof(ec_smt), &context->slavelist[slave].SM[1], EC_TIMEOUTRET3);
               EC_PRINT("    SM1 Type:%d StartAddr:%4.4x Flags:%8.8x\n", 
                   context->slavelist[slave].SMtype[1], 
                   context->slavelist[slave].SM[1].StartAddr, 
                   context->slavelist[slave].SM[1].SMflags);   
            }
            /* program SM2 to SMx */
            for( nSM = 2 ; nSM < EC_MAXSM ; nSM++ )
            {   
               if (context->slavelist[slave].SM[nSM].StartAddr)
               {
                  /* check if SM length is zero -> clear enable flag */
                  if( context->slavelist[slave].SM[nSM].SMlength == 0) 
                  {
                     context->slavelist[slave].SM[nSM].SMflags = 
                        htoel( etohl(context->slavelist[slave].SM[nSM].SMflags) & EC_SMENABLEMASK);
                  }
                  ecx_FPWR(context->port, configadr, ECT_REG_SM0 + (nSM * sizeof(ec_smt)),
                     sizeof(ec_smt), &context->slavelist[slave].SM[nSM], EC_TIMEOUTRET3);
                  EC_PRINT("    SM%d Type:%d StartAddr:%4.4x Flags:%8.8x\n", nSM,
                      context->slavelist[slave].SMtype[nSM], 
                      context->slavelist[slave].SM[nSM].StartAddr, 
                      context->slavelist[slave].SM[nSM].SMflags);   
               }
            }
            if (context->slavelist[slave].Ibits > 7)
            {
               context->slavelist[slave].Ibytes = (context->slavelist[slave].Ibits + 7) / 8;
            }
            if (context->slavelist[slave].Obits > 7)
            {
               context->slavelist[slave].Obytes = (context->slavelist[slave].Obits + 7) / 8;
            }
            FMMUc = context->slavelist[slave].FMMUunused;
            SMc = 0;
            BitCount = 0;
            ByteCount = 0;
            EndAddr = 0;
            FMMUsize = 0;
            FMMUdone = 0;
            /* create output mapping */
            if (context->slavelist[slave].Obits)
            {
               EC_PRINT("  OUTPUT MAPPING\n");
               /* search for SM that contribute to the output mapping */
               while ( (SMc < (EC_MAXSM - 1)) && (FMMUdone < ((context->slavelist[slave].Obits + 7) / 8)))
               {   
                  EC_PRINT("    FMMU %d\n", FMMUc);
                  while ( (SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 3)) SMc++;
                  EC_PRINT("      SM%d\n", SMc);
                  context->slavelist[slave].FMMU[FMMUc].PhysStart = 
                     context->slavelist[slave].SM[SMc].StartAddr;
                  SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength);
                  ByteCount += SMlength;
                  BitCount += SMlength * 8;
                  EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength;
                  while ( (BitCount < context->slavelist[slave].Obits) && (SMc < (EC_MAXSM - 1)) ) /* more SM for output */
                  {
                     SMc++;
                     while ( (SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 3)) SMc++;
                     /* if addresses from more SM connect use one FMMU otherwise break up in mutiple FMMU */
                     if ( etohs(context->slavelist[slave].SM[SMc].StartAddr) > EndAddr ) 
                     {
                        break;
                     }
                     EC_PRINT("      SM%d\n", SMc);
                     SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength);
                     ByteCount += SMlength;
                     BitCount += SMlength * 8;
                     EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength;               
                  }   

                  /* bit oriented slave */
                  if (!context->slavelist[slave].Obytes)
                  {   
                     context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(LogAddr);
                     context->slavelist[slave].FMMU[FMMUc].LogStartbit = BitPos;
                     BitPos += context->slavelist[slave].Obits - 1;
                     if (BitPos > 7)
                     {
                        LogAddr++;
                        BitPos -= 8;
                     }   
                     FMMUsize = LogAddr - etohl(context->slavelist[slave].FMMU[FMMUc].LogStart) + 1;
                     context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
                     context->slavelist[slave].FMMU[FMMUc].LogEndbit = BitPos;
                     BitPos ++;
                     if (BitPos > 7)
                     {
                        LogAddr++;
                        BitPos -= 8;
                     }   
                  }
                  /* byte oriented slave */
                  else
                  {
                     if (BitPos)
                     {
                        LogAddr++;
                        BitPos = 0;
                     }   
                     context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(LogAddr);
                     context->slavelist[slave].FMMU[FMMUc].LogStartbit = BitPos;
                     BitPos = 7;
                     FMMUsize = ByteCount;
                     if ((FMMUsize + FMMUdone)> (int)context->slavelist[slave].Obytes)
                     {
                        FMMUsize = context->slavelist[slave].Obytes - FMMUdone;
                     }
                     LogAddr += FMMUsize;
                     context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
                     context->slavelist[slave].FMMU[FMMUc].LogEndbit = BitPos;
                     BitPos = 0;
                  }
                  FMMUdone += FMMUsize;
                  context->slavelist[slave].FMMU[FMMUc].PhysStartBit = 0;
                  context->slavelist[slave].FMMU[FMMUc].FMMUtype = 2;
                  context->slavelist[slave].FMMU[FMMUc].FMMUactive = 1;
                  /* program FMMU for output */
                  ecx_FPWR(context->port, configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc),
                     sizeof(ec_fmmut), &(context->slavelist[slave].FMMU[FMMUc]), EC_TIMEOUTRET3);
                  context->grouplist[group].outputsWKC++;
                  if (!context->slavelist[slave].outputs)
                  {   
                     context->slavelist[slave].outputs = 
                        (uint8 *)(pIOmap) + etohl(context->slavelist[slave].FMMU[FMMUc].LogStart);
                     context->slavelist[slave].Ostartbit = 
                        context->slavelist[slave].FMMU[FMMUc].LogStartbit;
                     EC_PRINT("    slave %d Outputs %p startbit %d\n", 
                        slave, 
                        context->slavelist[slave].outputs, 
                        context->slavelist[slave].Ostartbit);
                  }
                  FMMUc++;
               }   
               context->slavelist[slave].FMMUunused = FMMUc;
               diff = LogAddr - oLogAddr;
               oLogAddr = LogAddr;
               if ((segmentsize + diff) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM))
               {
                  context->grouplist[group].IOsegment[currentsegment] = segmentsize;
                  if (currentsegment < (EC_MAXIOSEGMENTS - 1))
                  {
                     currentsegment++;
                     segmentsize = diff;   
                  }
               }
               else
               {
                  segmentsize += diff;
               }
            }
         }   
      }
      if (BitPos)
      {
         LogAddr++;
         oLogAddr = LogAddr;
         BitPos = 0;
         if ((segmentsize + 1) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM))
         {
            context->grouplist[group].IOsegment[currentsegment] = segmentsize;
            if (currentsegment < (EC_MAXIOSEGMENTS - 1))
            {
               currentsegment++;
               segmentsize = 1;   
            }
         }
         else
         {
            segmentsize += 1;
         }
      }   
      context->grouplist[group].outputs = pIOmap;
      context->grouplist[group].Obytes = LogAddr;
      context->grouplist[group].nsegments = currentsegment + 1;
      context->grouplist[group].Isegment = currentsegment;
      context->grouplist[group].Ioffset = segmentsize;
      if (!group)
      {   
         context->slavelist[0].outputs = pIOmap;
         context->slavelist[0].Obytes = LogAddr; /* store output bytes in master record */
      }   
      
      /* do input mapping of slave and program FMMUs */
      for (slave = 1; slave <= *(context->slavecount); slave++)
      {
         configadr = context->slavelist[slave].configadr;
         FMMUc = context->slavelist[slave].FMMUunused;
         if (context->slavelist[slave].Obits) /* find free FMMU */
         {
            while ( context->slavelist[slave].FMMU[FMMUc].LogStart ) FMMUc++;
         }
         SMc = 0;
         BitCount = 0;
         ByteCount = 0;
         EndAddr = 0;
         FMMUsize = 0;
         FMMUdone = 0;
         /* create input mapping */
         if (context->slavelist[slave].Ibits)
         {
            EC_PRINT(" =Slave %d, INPUT MAPPING\n", slave);
            /* search for SM that contribute to the input mapping */
            while ( (SMc < (EC_MAXSM - 1)) && (FMMUdone < ((context->slavelist[slave].Ibits + 7) / 8)))
            {   
               EC_PRINT("    FMMU %d\n", FMMUc);
               while ( (SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 4)) SMc++;
               EC_PRINT("      SM%d\n", SMc);
               context->slavelist[slave].FMMU[FMMUc].PhysStart = 
                  context->slavelist[slave].SM[SMc].StartAddr;
               SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength);
               ByteCount += SMlength;
               BitCount += SMlength * 8;
               EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength;
               while ( (BitCount < context->slavelist[slave].Ibits) && (SMc < (EC_MAXSM - 1)) ) /* more SM for input */
               {
                  SMc++;
                  while ( (SMc < (EC_MAXSM - 1)) && (context->slavelist[slave].SMtype[SMc] != 4)) SMc++;
                  /* if addresses from more SM connect use one FMMU otherwise break up in mutiple FMMU */
                  if ( etohs(context->slavelist[slave].SM[SMc].StartAddr) > EndAddr ) 
                  {
                     break;
                  }
                  EC_PRINT("      SM%d\n", SMc);
                  SMlength = etohs(context->slavelist[slave].SM[SMc].SMlength);
                  ByteCount += SMlength;
                  BitCount += SMlength * 8;
                  EndAddr = etohs(context->slavelist[slave].SM[SMc].StartAddr) + SMlength;               
               }   

               /* bit oriented slave */
               if (!context->slavelist[slave].Ibytes)
               {   
                  context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(LogAddr);
                  context->slavelist[slave].FMMU[FMMUc].LogStartbit = BitPos;
                  BitPos += context->slavelist[slave].Ibits - 1;
                  if (BitPos > 7)
                  {
                     LogAddr++;
                     BitPos -= 8;
                  }   
                  FMMUsize = LogAddr - etohl(context->slavelist[slave].FMMU[FMMUc].LogStart) + 1;
                  context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
                  context->slavelist[slave].FMMU[FMMUc].LogEndbit = BitPos;
                  BitPos ++;
                  if (BitPos > 7)
                  {
                     LogAddr++;
                     BitPos -= 8;
                  }   
               }
               /* byte oriented slave */
               else
               {
                  if (BitPos)
                  {
                     LogAddr++;
                     BitPos = 0;
                  }   
                  context->slavelist[slave].FMMU[FMMUc].LogStart = htoel(LogAddr);
                  context->slavelist[slave].FMMU[FMMUc].LogStartbit = BitPos;
                  BitPos = 7;
                  FMMUsize = ByteCount;
                  if ((FMMUsize + FMMUdone)> (int)context->slavelist[slave].Ibytes)
                  {
                     FMMUsize = context->slavelist[slave].Ibytes - FMMUdone;
                  }
                  LogAddr += FMMUsize;
                  context->slavelist[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
                  context->slavelist[slave].FMMU[FMMUc].LogEndbit = BitPos;
                  BitPos = 0;
               }
               FMMUdone += FMMUsize;
               if (context->slavelist[slave].FMMU[FMMUc].LogLength)
               {   
                  context->slavelist[slave].FMMU[FMMUc].PhysStartBit = 0;
                  context->slavelist[slave].FMMU[FMMUc].FMMUtype = 1;
                  context->slavelist[slave].FMMU[FMMUc].FMMUactive = 1;
                  /* program FMMU for input */
                  ecx_FPWR(context->port, configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc), 
                     sizeof(ec_fmmut), &(context->slavelist[slave].FMMU[FMMUc]), EC_TIMEOUTRET3);
                  /* add one for an input FMMU */
                  context->grouplist[group].inputsWKC++;
               }   
               if (!context->slavelist[slave].inputs)
               {   
                  context->slavelist[slave].inputs = 
                     (uint8 *)(pIOmap) + etohl(context->slavelist[slave].FMMU[FMMUc].LogStart);
                  context->slavelist[slave].Istartbit = 
                     context->slavelist[slave].FMMU[FMMUc].LogStartbit;
                  EC_PRINT("    Inputs %p startbit %d\n", 
                     context->slavelist[slave].inputs, 
                     context->slavelist[slave].Istartbit);
               }
               FMMUc++;
            }   
            context->slavelist[slave].FMMUunused = FMMUc;
            diff = LogAddr - oLogAddr;
            oLogAddr = LogAddr;
            if ((segmentsize + diff) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM))
            {
               context->grouplist[group].IOsegment[currentsegment] = segmentsize;
               if (currentsegment < (EC_MAXIOSEGMENTS - 1))
               {
                  currentsegment++;
                  segmentsize = diff;   
               }
            }
            else
            {
               segmentsize += diff;
            }   
         }

         ecx_eeprom2pdi(context, slave); /* set Eeprom control to PDI */         
         ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_SAFE_OP) , EC_TIMEOUTRET3); /* set safeop status */
                  
         if (context->slavelist[slave].blockLRW)
         {    
            context->grouplist[group].blockLRW++;                     
         }
         context->grouplist[group].Ebuscurrent += context->slavelist[slave].Ebuscurrent;
      }
      if (BitPos)
      {
         LogAddr++;
         oLogAddr = LogAddr;
         BitPos = 0;
         if ((segmentsize + 1) > (EC_MAXLRWDATA - EC_FIRSTDCDATAGRAM))
         {
            context->grouplist[group].IOsegment[currentsegment] = segmentsize;
            if (currentsegment < (EC_MAXIOSEGMENTS - 1))
            {
               currentsegment++;
               segmentsize = 1;   
            }
         }
         else
         {
            segmentsize += 1;
         }
      }   
      context->grouplist[group].IOsegment[currentsegment] = segmentsize;
      context->grouplist[group].nsegments = currentsegment + 1;
      context->grouplist[group].inputs = (uint8 *)(pIOmap) + context->grouplist[group].Obytes;
      context->grouplist[group].Ibytes = LogAddr - context->grouplist[group].Obytes;
      if (!group)
      {   
         context->slavelist[0].inputs = (uint8 *)(pIOmap) + context->slavelist[0].Obytes;
         context->slavelist[0].Ibytes = LogAddr - context->slavelist[0].Obytes; /* store input bytes in master record */
      }   

      EC_PRINT("IOmapSize %d\n", LogAddr - context->grouplist[group].logstartaddr);      
   
      return (LogAddr - context->grouplist[group].logstartaddr);
   }
   
   return 0;
}   
예제 #10
0
/** Enumerate and init all slaves.
 *
 * @param[in]  context        = context struct
 * @param[in] usetable     = TRUE when using configtable to init slaves, FALSE otherwise
 * @return Workcounter of slave discover datagram = number of slaves found
 */
int ecx_config_init(ecx_contextt *context, uint8 usetable)
{
   uint16 w, slave, ADPh, configadr, ssigen;
   uint16 topology, estat;
   int16 topoc, slavec, aliasadr;
   uint8 b,h;
   uint8 zbuf[64];
   uint8 SMc;
   uint32 eedat;
   int wkc, cindex, nSM, lp;

   EC_PRINT("ec_config_init %d\n",usetable);
   *(context->slavecount) = 0;
   /* clean ec_slave array */
   memset(context->slavelist, 0x00, sizeof(ec_slavet) * context->maxslave);
   memset(&zbuf, 0x00, sizeof(zbuf));
   memset(context->grouplist, 0x00, sizeof(ec_groupt) * context->maxgroup);
   /* clear slave eeprom cache */
   ecx_siigetbyte(context, 0, EC_MAXEEPBUF);
   
   for(lp = 0; lp < context->maxgroup; lp++)
   {
      context->grouplist[lp].logstartaddr = lp << 16; /* default start address per group entry */
   }
   /* make special pre-init register writes to enable MAC[1] local administered bit *
    * setting for old netX100 slaves */
   b = 0x00;
   ecx_BWR(context->port, 0x0000, ECT_REG_DLALIAS, sizeof(b), &b, EC_TIMEOUTRET3);    /* Ignore Alias register */
   b = EC_STATE_INIT | EC_STATE_ACK;
   ecx_BWR(context->port, 0x0000, ECT_REG_ALCTL, sizeof(b), &b, EC_TIMEOUTRET3);      /* Reset all slaves to Init */
   /* netX100 should now be happy */
   
   wkc = ecx_BWR(context->port, 0x0000, ECT_REG_ALCTL, sizeof(b), &b, EC_TIMEOUTRET3);      /* Reset all slaves to Init */
   printf("wkc = %d\n",wkc);
   
   w = 0x0000;
   wkc = ecx_BRD(context->port, 0x0000, ECT_REG_TYPE, sizeof(w), &w, EC_TIMEOUTSAFE);   /* detect number of slaves */
   if (wkc > 0)
   {
      *(context->slavecount) = wkc;
      b = 0x00;
      ecx_BWR(context->port, 0x0000, ECT_REG_DLPORT, sizeof(b), &b, EC_TIMEOUTRET3);     /* deact loop manual */
      w = htoes(0x0004);
      ecx_BWR(context->port, 0x0000, ECT_REG_IRQMASK, sizeof(w), &w, EC_TIMEOUTRET3);    /* set IRQ mask */
      ecx_BWR(context->port, 0x0000, ECT_REG_RXERR, 8, &zbuf, EC_TIMEOUTRET3);           /* reset CRC counters */
      ecx_BWR(context->port, 0x0000, ECT_REG_FMMU0, 16 * 3, &zbuf, EC_TIMEOUTRET3);      /* reset FMMU's */
      ecx_BWR(context->port, 0x0000, ECT_REG_SM0, 8 * 4, &zbuf, EC_TIMEOUTRET3);         /* reset SyncM */
      ecx_BWR(context->port, 0x0000, ECT_REG_DCSYSTIME, 4, &zbuf, EC_TIMEOUTRET3);       /* reset system time+ofs */
      w = htoes(0x1000);
      ecx_BWR(context->port, 0x0000, ECT_REG_DCSPEEDCNT, sizeof(w), &w, EC_TIMEOUTRET3); /* DC speedstart */
      w = htoes(0x0c00);
      ecx_BWR(context->port, 0x0000, ECT_REG_DCTIMEFILT, sizeof(w), &w, EC_TIMEOUTRET3); /* DC filt expr */
      b = 0x00;
      ecx_BWR(context->port, 0x0000, ECT_REG_DLALIAS, sizeof(b), &b, EC_TIMEOUTRET3);    /* Ignore Alias register */
      b = EC_STATE_INIT | EC_STATE_ACK;
      ecx_BWR(context->port, 0x0000, ECT_REG_ALCTL, sizeof(b), &b, EC_TIMEOUTRET3);      /* Reset all slaves to Init */
      b = 2;
      ecx_BWR(context->port, 0x0000, ECT_REG_EEPCFG, sizeof(b), &b , EC_TIMEOUTRET3);    /* force Eeprom from PDI */
      b = 0;
      ecx_BWR(context->port, 0x0000, ECT_REG_EEPCFG, sizeof(b), &b , EC_TIMEOUTRET3);    /* set Eeprom to master */
      
      for (slave = 1; slave <= *(context->slavecount); slave++)
      {
         ADPh = (uint16)(1 - slave);
         context->slavelist[slave].Itype = 
            etohs(ecx_APRDw(context->port, ADPh, ECT_REG_PDICTL, EC_TIMEOUTRET3)); /* read interface type of slave */
         /* a node offset is used to improve readibility of network frames */
         /* this has no impact on the number of addressable slaves (auto wrap around) */
         ecx_APWRw(context->port, ADPh, ECT_REG_STADR, htoes(slave + EC_NODEOFFSET) , EC_TIMEOUTRET3); /* set node address of slave */
         if (slave == 1) 
         {
            b = 1; /* kill non ecat frames for first slave */
         }
         else 
         {
            b = 0; /* pass all frames for following slaves */
         }
         ecx_APWRw(context->port, ADPh, ECT_REG_DLCTL, htoes(b), EC_TIMEOUTRET3); /* set non ecat frame behaviour */
         configadr = etohs(ecx_APRDw(context->port, ADPh, ECT_REG_STADR, EC_TIMEOUTRET3));
         context->slavelist[slave].configadr = configadr;
         ecx_FPRD(context->port, configadr, ECT_REG_ALIAS, sizeof(aliasadr), &aliasadr, EC_TIMEOUTRET3);
         context->slavelist[slave].aliasadr = etohs(aliasadr);
         ecx_FPRD(context->port, configadr, ECT_REG_EEPSTAT, sizeof(estat), &estat, EC_TIMEOUTRET3);
         estat = etohs(estat);
         if (estat & EC_ESTAT_R64) /* check if slave can read 8 byte chunks */
         {
            context->slavelist[slave].eep_8byte = 1;
         }
         ecx_readeeprom1(context, slave, ECT_SII_MANUF); /* Manuf */
      }
      for (slave = 1; slave <= *(context->slavecount); slave++)
      {
         context->slavelist[slave].eep_man = 
            etohl(ecx_readeeprom2(context, slave, EC_TIMEOUTEEP)); /* Manuf */
         ecx_readeeprom1(context, slave, ECT_SII_ID); /* ID */
      }
      for (slave = 1; slave <= *(context->slavecount); slave++)
      {
         context->slavelist[slave].eep_id = 
            etohl(ecx_readeeprom2(context, slave, EC_TIMEOUTEEP)); /* ID */
         ecx_readeeprom1(context, slave, ECT_SII_REV); /* revision */
      }
      for (slave = 1; slave <= *(context->slavecount); slave++)
      {
         context->slavelist[slave].eep_rev = 
            etohl(ecx_readeeprom2(context, slave, EC_TIMEOUTEEP)); /* revision */
         ecx_readeeprom1(context, slave, ECT_SII_RXMBXADR); /* write mailbox address + mailboxsize */
      }
      for (slave = 1; slave <= *(context->slavecount); slave++)
      {
         eedat = etohl(ecx_readeeprom2(context, slave, EC_TIMEOUTEEP)); /* write mailbox address and mailboxsize */
         context->slavelist[slave].mbx_wo = (uint16)LO_WORD(eedat);
         context->slavelist[slave].mbx_l = (uint16)HI_WORD(eedat);
         if (context->slavelist[slave].mbx_l > 0) 
         {
            ecx_readeeprom1(context, slave, ECT_SII_TXMBXADR); /* read mailbox offset */
         }
      }
      for (slave = 1; slave <= *(context->slavecount); slave++)
      {
         if (context->slavelist[slave].mbx_l > 0) 
         {
            eedat = etohl(ecx_readeeprom2(context, slave, EC_TIMEOUTEEP)); /* read mailbox offset */
            context->slavelist[slave].mbx_ro = (uint16)LO_WORD(eedat); /* read mailbox offset */
            context->slavelist[slave].mbx_rl = (uint16)HI_WORD(eedat); /*read mailbox length */
            if (context->slavelist[slave].mbx_rl == 0)
            {
               context->slavelist[slave].mbx_rl = context->slavelist[slave].mbx_l;
            }
         }
         configadr = context->slavelist[slave].configadr;
         if ((etohs(ecx_FPRDw(context->port, configadr, ECT_REG_ESCSUP, EC_TIMEOUTRET3)) & 0x04) > 0)  /* Support DC? */
         {   
            context->slavelist[slave].hasdc = TRUE;
         }
         else
         {
            context->slavelist[slave].hasdc = FALSE;
         }
         topology = etohs(ecx_FPRDw(context->port, configadr, ECT_REG_DLSTAT, EC_TIMEOUTRET3)); /* extract topology from DL status */
         h = 0; 
         b = 0;
         if ((topology & 0x0300) == 0x0200) /* port0 open and communication established */
         {
            h++;
            b |= 0x01;
         }
         if ((topology & 0x0c00) == 0x0800) /* port1 open and communication established */
         {
            h++;
            b |= 0x02;
         }
         if ((topology & 0x3000) == 0x2000) /* port2 open and communication established */
         {
            h++;
            b |= 0x04;
         }
         if ((topology & 0xc000) == 0x8000) /* port3 open and communication established */
         {
            h++;
            b |= 0x08;
         }
         /* ptype = Physical type*/
         context->slavelist[slave].ptype = 
            LO_BYTE(etohs(ecx_FPRDw(context->port, configadr, ECT_REG_PORTDES, EC_TIMEOUTRET3)));
         context->slavelist[slave].topology = h;
         context->slavelist[slave].activeports = b;
         /* 0=no links, not possible             */
         /* 1=1 link  , end of line              */
         /* 2=2 links , one before and one after */
         /* 3=3 links , split point              */
         /* 4=4 links , cross point              */
         /* search for parent */
         context->slavelist[slave].parent = 0; /* parent is master */
         if (slave > 1)
         {
            topoc = 0; 
            slavec = slave - 1;
            do
            {
               topology = context->slavelist[slavec].topology;
               if (topology == 1)
               {
                  topoc--; /* endpoint found */
               }
               if (topology == 3)
               {
                  topoc++; /* split found */
               }
               if (topology == 4)
               {
                  topoc += 2; /* cross found */
               }
               if (((topoc >= 0) && (topology > 1)) ||
                   (slavec == 1)) /* parent found */
               {
                  context->slavelist[slave].parent = slavec;
                  slavec = 1;
               }
               slavec--;
            }
            while (slavec > 0);
         }

         w = ecx_statecheck(context, slave, EC_STATE_INIT,  EC_TIMEOUTSTATE); //* check state change Init */
   
         /* set default mailbox configuration if slave has mailbox */
         if (context->slavelist[slave].mbx_l>0)
         {   
            context->slavelist[slave].SMtype[0] = 1;
            context->slavelist[slave].SMtype[1] = 2;
            context->slavelist[slave].SMtype[2] = 3;
            context->slavelist[slave].SMtype[3] = 4;
            context->slavelist[slave].SM[0].StartAddr = htoes(context->slavelist[slave].mbx_wo);
            context->slavelist[slave].SM[0].SMlength = htoes(context->slavelist[slave].mbx_l);
            context->slavelist[slave].SM[0].SMflags = htoel(EC_DEFAULTMBXSM0);
            context->slavelist[slave].SM[1].StartAddr = htoes(context->slavelist[slave].mbx_ro);
            context->slavelist[slave].SM[1].SMlength = htoes(context->slavelist[slave].mbx_rl);
            context->slavelist[slave].SM[1].SMflags = htoel(EC_DEFAULTMBXSM1);
            context->slavelist[slave].mbx_proto = 
               ecx_readeeprom(context, slave, ECT_SII_MBXPROTO, EC_TIMEOUTEEP);
         }   
         cindex = 0;
         #ifdef EC_VER1
         /* use configuration table ? */
         if (usetable)
         {
            cindex = ec_findconfig( context->slavelist[slave].eep_man, context->slavelist[slave].eep_id );
            context->slavelist[slave].configindex= cindex;
         }
         /* slave found in configuration table ? */
         if (cindex)
         {
            context->slavelist[slave].Dtype = ec_configlist[cindex].Dtype;            
            strcpy(context->slavelist[slave].name ,ec_configlist[cindex].name);
            context->slavelist[slave].Ibits = ec_configlist[cindex].Ibits;
            context->slavelist[slave].Obits = ec_configlist[cindex].Obits;
            if (context->slavelist[slave].Obits)
            {
               context->slavelist[slave].FMMU0func = 1;
            }
            if (context->slavelist[slave].Ibits)
            {
               context->slavelist[slave].FMMU1func = 2;
            }
            context->slavelist[slave].FMMU[0].FMMUactive = ec_configlist[cindex].FM0ac;
            context->slavelist[slave].FMMU[1].FMMUactive = ec_configlist[cindex].FM1ac;
            context->slavelist[slave].SM[2].StartAddr = htoes(ec_configlist[cindex].SM2a);
            context->slavelist[slave].SM[2].SMflags = htoel(ec_configlist[cindex].SM2f);
            /* simple (no mailbox) output slave found ? */
            if (context->slavelist[slave].Obits && !context->slavelist[slave].SM[2].StartAddr)
            {
               context->slavelist[slave].SM[0].StartAddr = htoes(0x0f00);
               context->slavelist[slave].SM[0].SMlength = htoes((context->slavelist[slave].Obits + 7) / 8);
               context->slavelist[slave].SM[0].SMflags = htoel(EC_DEFAULTDOSM0);         
               context->slavelist[slave].FMMU[0].FMMUactive = 1;
               context->slavelist[slave].FMMU[0].FMMUtype = 2;
               context->slavelist[slave].SMtype[0] = 3;
            }
            /* complex output slave */
            else
            {
               context->slavelist[slave].SM[2].SMlength = htoes((context->slavelist[slave].Obits + 7) / 8);
               context->slavelist[slave].SMtype[2] = 3;
            }   
            context->slavelist[slave].SM[3].StartAddr = htoes(ec_configlist[cindex].SM3a);
            context->slavelist[slave].SM[3].SMflags = htoel(ec_configlist[cindex].SM3f);
            /* simple (no mailbox) input slave found ? */
            if (context->slavelist[slave].Ibits && !context->slavelist[slave].SM[3].StartAddr)
            {
               context->slavelist[slave].SM[1].StartAddr = htoes(0x1000);
               context->slavelist[slave].SM[1].SMlength = htoes((context->slavelist[slave].Ibits + 7) / 8);
               context->slavelist[slave].SM[1].SMflags = htoel(0x00000000);         
               context->slavelist[slave].FMMU[1].FMMUactive = 1;
               context->slavelist[slave].FMMU[1].FMMUtype = 1;
               context->slavelist[slave].SMtype[1] = 4;
            }
            /* complex input slave */
            else
            {
               context->slavelist[slave].SM[3].SMlength = htoes((context->slavelist[slave].Ibits + 7) / 8);
               context->slavelist[slave].SMtype[3] = 4;
            }   
         }
         /* slave not in configuration table, find out via SII */
         else
         #endif
         {
            ssigen = ecx_siifind(context, slave, ECT_SII_GENERAL);
            /* SII general section */
            if (ssigen)
            {
               context->slavelist[slave].CoEdetails = ecx_siigetbyte(context, slave, ssigen + 0x07);
               context->slavelist[slave].FoEdetails = ecx_siigetbyte(context, slave, ssigen + 0x08);
               context->slavelist[slave].EoEdetails = ecx_siigetbyte(context, slave, ssigen + 0x09);
               context->slavelist[slave].SoEdetails = ecx_siigetbyte(context, slave, ssigen + 0x0a);
               if((ecx_siigetbyte(context, slave, ssigen + 0x0d) & 0x02) > 0)
               {
                  context->slavelist[slave].blockLRW = 1;
                  context->slavelist[0].blockLRW++;                  
               }   
               context->slavelist[slave].Ebuscurrent = ecx_siigetbyte(context, slave, ssigen + 0x0e);
               context->slavelist[slave].Ebuscurrent += ecx_siigetbyte(context, slave, ssigen + 0x0f) << 8;
               context->slavelist[0].Ebuscurrent += context->slavelist[slave].Ebuscurrent;
            }
            /* SII strings section */
            if (ecx_siifind(context, slave, ECT_SII_STRING) > 0)
            {
               ecx_siistring(context, context->slavelist[slave].name, slave, 1);
            }
            /* no name for slave found, use constructed name */
            else
            {
               sprintf(context->slavelist[slave].name, "? M:%8.8x I:%8.8x",
                       (unsigned int)context->slavelist[slave].eep_man, 
                       (unsigned int)context->slavelist[slave].eep_id);
            }
            /* SII SM section */
            nSM = ecx_siiSM(context, slave, context->eepSM);
            if (nSM>0)
            {   
               context->slavelist[slave].SM[0].StartAddr = htoes(context->eepSM->PhStart);
               context->slavelist[slave].SM[0].SMlength = htoes(context->eepSM->Plength);
               context->slavelist[slave].SM[0].SMflags = 
                  htoel((context->eepSM->Creg) + (context->eepSM->Activate << 16));
               SMc = 1;
               while ((SMc < EC_MAXSM) &&  ecx_siiSMnext(context, slave, context->eepSM, SMc))
               {
                  context->slavelist[slave].SM[SMc].StartAddr = htoes(context->eepSM->PhStart);
                  context->slavelist[slave].SM[SMc].SMlength = htoes(context->eepSM->Plength);
                  context->slavelist[slave].SM[SMc].SMflags = 
                     htoel((context->eepSM->Creg) + (context->eepSM->Activate << 16));
                  SMc++;
               }   
            }   
            /* SII FMMU section */
            if (ecx_siiFMMU(context, slave, context->eepFMMU))
            {
               if (context->eepFMMU->FMMU0 !=0xff) 
               {
                  context->slavelist[slave].FMMU0func = context->eepFMMU->FMMU0;
               }
               if (context->eepFMMU->FMMU1 !=0xff) 
               {
                  context->slavelist[slave].FMMU1func = context->eepFMMU->FMMU1;
               }
               if (context->eepFMMU->FMMU2 !=0xff) 
               {
                  context->slavelist[slave].FMMU2func = context->eepFMMU->FMMU2;
               }
               if (context->eepFMMU->FMMU3 !=0xff) 
               {
                  context->slavelist[slave].FMMU3func = context->eepFMMU->FMMU3;
               }
            }            
         }   

         if (context->slavelist[slave].mbx_l > 0)
         {
            if (context->slavelist[slave].SM[0].StartAddr == 0x0000) /* should never happen */
            {
               EC_PRINT("Slave %d has no proper mailbox in configuration, try default.\n", slave);
               context->slavelist[slave].SM[0].StartAddr = htoes(0x1000);
               context->slavelist[slave].SM[0].SMlength = htoes(0x0080);
               context->slavelist[slave].SM[0].SMflags = htoel(EC_DEFAULTMBXSM0);
               context->slavelist[slave].SMtype[0] = 1;               
            }         
            if (context->slavelist[slave].SM[1].StartAddr == 0x0000) /* should never happen */
            {
               EC_PRINT("Slave %d has no proper mailbox out configuration, try default.\n", slave);
               context->slavelist[slave].SM[1].StartAddr = htoes(0x1080);
               context->slavelist[slave].SM[1].SMlength = htoes(0x0080);
               context->slavelist[slave].SM[1].SMflags = htoel(EC_DEFAULTMBXSM1);
               context->slavelist[slave].SMtype[1] = 2;
            }         
            /* program SM0 mailbox in and SM1 mailbox out for slave */
            /* writing both SM in one datagram will solve timing issue in old NETX */
            ecx_FPWR(context->port, configadr, ECT_REG_SM0, sizeof(ec_smt) * 2, 
               &(context->slavelist[slave].SM[0]), EC_TIMEOUTRET3);
         } 
         /* request pre_op for slave */
         ecx_FPWRw(context->port, configadr, ECT_REG_ALCTL, htoes(EC_STATE_PRE_OP | EC_STATE_ACK) , EC_TIMEOUTRET3); /* set preop status */
      }
   }   
   return wkc;
}
예제 #11
0
/** FoE read, blocking.
 * 
 * @param[in]  slave		= Slave number.
 * @param[in]  filename		= Filename of file to read.
 * @param[in]  password     = password.
 * @param[in,out] psize		= Size in bytes of file buffer, returns bytes read from file.
 * @param[out] p			= Pointer to file buffer
 * @param[in]  timeout		= Timeout in us, standard is EC_TIMEOUTRXM
 * @return Workcounter from last slave response
 */
int ec_FOEread(uint16 slave, char *filename, uint32 password, int *psize, void *p, int timeout)
{
    ec_FOEt *FOEp, *aFOEp;
	int wkc;
    int32 dataread = 0;
	int32 buffersize, packetnumber, prevpacket = 0;
	uint16 fnsize, maxdata, segmentdata;
    ec_mbxbuft MbxIn, MbxOut;
    uint8 cnt;
    boolean worktodo;

	buffersize = *psize;
    ec_clearmbx(&MbxIn);
	/* Empty slave out mailbox if something is in. Timout set to 0 */
    wkc = ec_mbxreceive(slave, (ec_mbxbuft *)&MbxIn, 0);
    ec_clearmbx(&MbxOut);
    aFOEp = (ec_FOEt *)&MbxIn;
    FOEp = (ec_FOEt *)&MbxOut;
	fnsize = strlen(filename);
	maxdata = ec_slave[slave].mbx_l - 12;
	if (fnsize > maxdata)
		fnsize = maxdata;
    FOEp->MbxHeader.length = htoes(0x0006 + fnsize);
    FOEp->MbxHeader.address = htoes(0x0000);
    FOEp->MbxHeader.priority = 0x00;
	/* get new mailbox count value, used as session handle */
    cnt = ec_nextmbxcnt(ec_slave[slave].mbx_cnt);
    ec_slave[slave].mbx_cnt = cnt;
    FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + (cnt << 4); /* FoE */
    FOEp->OpCode = ECT_FOE_READ;
    FOEp->Password = htoel(password);
	/* copy filename in mailbox */
	memcpy(&FOEp->FileName[0], filename, fnsize);
	/* send FoE request to slave */
    wkc = ec_mbxsend(slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
    if (wkc > 0) /* succeeded to place mailbox in slave ? */
    {
		do
		{	
			worktodo = FALSE;
			/* clean mailboxbuffer */
			ec_clearmbx(&MbxIn);
			/* read slave response */
			wkc = ec_mbxreceive(slave, (ec_mbxbuft *)&MbxIn, timeout);
			if (wkc > 0) /* succeeded to read slave response ? */
			{
				/* slave response should be FoE */
				if ((aFOEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_FOE)
				{
					if(aFOEp->OpCode == ECT_FOE_DATA)
					{
						segmentdata = etohs(aFOEp->MbxHeader.length) - 0x0006;
						packetnumber = etohl(aFOEp->PacketNumber);
						if ((packetnumber == ++prevpacket) && (dataread + segmentdata <= buffersize))
						{
							memcpy(p, &aFOEp->Data[0], segmentdata);
							dataread += segmentdata;
							p += segmentdata;
							if (segmentdata == maxdata)
								worktodo = TRUE; 
							FOEp->MbxHeader.length = htoes(0x0006);
							FOEp->MbxHeader.address = htoes(0x0000);
							FOEp->MbxHeader.priority = 0x00;
							/* get new mailbox count value */
							cnt = ec_nextmbxcnt(ec_slave[slave].mbx_cnt);
							ec_slave[slave].mbx_cnt = cnt;
							FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + (cnt << 4); /* FoE */
							FOEp->OpCode = ECT_FOE_ACK;
							FOEp->PacketNumber = htoel(packetnumber);
							/* send FoE ack to slave */
							wkc = ec_mbxsend(slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
							if (wkc <= 0)
								worktodo = FALSE;
						}
						else
						{
							/* FoE error */
							wkc = -EC_ERR_TYPE_FOE_BUF2SMALL;
						}
					}
					else
					if(aFOEp->OpCode == ECT_FOE_ERROR)
					{
						/* FoE error */
						wkc = -EC_ERR_TYPE_FOE_ERROR;
					}
					else
					{
						/* unexpected mailbox received */
						wkc = -EC_ERR_TYPE_PACKET_ERROR;
					}
				}
				else
				{
					/* unexpected mailbox received */
					wkc = -EC_ERR_TYPE_PACKET_ERROR;
				}
				*psize = dataread;
			}
		} while (worktodo);	
	}
	
	return wkc;
}	
예제 #12
0
/** FoE write, blocking.
 * 
 * @param[in]  context        = context struct
 * @param[in]  slave      = Slave number.
 * @param[in]  filename   = Filename of file to write.
 * @param[in]  password   = password.
 * @param[in]  psize      = Size in bytes of file buffer.
 * @param[out] p          = Pointer to file buffer
 * @param[in]  timeout    = Timeout per mailbox cycle in us, standard is EC_TIMEOUTRXM
 * @return Workcounter from last slave response
 */
int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 password, int psize, void *p, int timeout)
{
   ec_FOEt *FOEp, *aFOEp;
   int wkc;
   int32 packetnumber, sendpacket = 0;
   uint16 fnsize, maxdata;
   int segmentdata;
   ec_mbxbuft MbxIn, MbxOut;
   uint8 cnt;
   boolean worktodo, dofinalzero;
   int tsize;

   ec_clearmbx(&MbxIn);
   /* Empty slave out mailbox if something is in. Timout set to 0 */
   wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, 0);
   ec_clearmbx(&MbxOut);
   aFOEp = (ec_FOEt *)&MbxIn;
   FOEp = (ec_FOEt *)&MbxOut;
   dofinalzero = FALSE;
   fnsize = strlen(filename);
   maxdata = context->slavelist[slave].mbx_l - 12;
   if (fnsize > maxdata)
   {
      fnsize = maxdata;
   }
   FOEp->MbxHeader.length = htoes(0x0006 + fnsize);
   FOEp->MbxHeader.address = htoes(0x0000);
   FOEp->MbxHeader.priority = 0x00;
   /* get new mailbox count value, used as session handle */
   cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt);
   context->slavelist[slave].mbx_cnt = cnt;
   FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + (cnt << 4); /* FoE */
   FOEp->OpCode = ECT_FOE_WRITE;
   FOEp->Password = htoel(password);
   /* copy filename in mailbox */
   memcpy(&FOEp->FileName[0], filename, fnsize);
   /* send FoE request to slave */
   wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
   if (wkc > 0) /* succeeded to place mailbox in slave ? */
   {
      do
      {   
         worktodo = FALSE;
         /* clean mailboxbuffer */
         ec_clearmbx(&MbxIn);
         /* read slave response */
         wkc = ecx_mbxreceive(context, slave, (ec_mbxbuft *)&MbxIn, timeout);
         if (wkc > 0) /* succeeded to read slave response ? */
         {
            /* slave response should be FoE */
            if ((aFOEp->MbxHeader.mbxtype & 0x0f) == ECT_MBXT_FOE)
            {
               switch (aFOEp->OpCode)
               {
                  case ECT_FOE_ACK:
                  {
                     packetnumber = etohl(aFOEp->PacketNumber);
                     if (packetnumber == sendpacket)
                     {
                        if (context->FOEhook)
                        {
                           context->FOEhook(slave, packetnumber, psize);
                        }
                        tsize = psize;
                        if (tsize > maxdata)
                        {
                           tsize = maxdata;
                        }
                        if(tsize || dofinalzero)
                        {
                           worktodo = TRUE; 
                           dofinalzero = FALSE;
                           segmentdata = tsize;
                           psize -= segmentdata;
                           /* if last packet was full size, add a zero size packet as final */
                           /* EOF is defined as packetsize < full packetsize */
                           if (!psize && (segmentdata == maxdata))
                           {
                              dofinalzero = TRUE;
                           }
                           FOEp->MbxHeader.length = htoes(0x0006 + segmentdata);
                           FOEp->MbxHeader.address = htoes(0x0000);
                           FOEp->MbxHeader.priority = 0x00;
                           /* get new mailbox count value */
                           cnt = ec_nextmbxcnt(context->slavelist[slave].mbx_cnt);
                           context->slavelist[slave].mbx_cnt = cnt;
                           FOEp->MbxHeader.mbxtype = ECT_MBXT_FOE + (cnt << 4); /* FoE */
                           FOEp->OpCode = ECT_FOE_DATA;
                           sendpacket++;
                           FOEp->PacketNumber = htoel(sendpacket);
                           memcpy(&FOEp->Data[0], p, segmentdata);
                           p = (uint8 *)p + segmentdata;
                           /* send FoE data to slave */
                           wkc = ecx_mbxsend(context, slave, (ec_mbxbuft *)&MbxOut, EC_TIMEOUTTXM);
                           if (wkc <= 0)
                           {   
                              worktodo = FALSE;
                           }
                        }
                     }
                     else
                     {
                        /* FoE error */
                        wkc = -EC_ERR_TYPE_FOE_PACKETNUMBER;
                     }
                     break;
                  }
                  case ECT_FOE_BUSY:
                  {
                     /* resend if data has been send before */
                     /* otherwise ignore */
                     if (sendpacket)
                     {
                        if (!psize)
                        {
                           dofinalzero = TRUE;
                        }
                        psize += segmentdata;
                        p = (uint8 *)p - segmentdata;
                        --sendpacket;
                     }
                     break;
                  }
                  case ECT_FOE_ERROR:
                  {
                     /* FoE error */
                     wkc = -EC_ERR_TYPE_FOE_ERROR;
                     break;
                  }
                  default:
                  {
                     /* unexpected mailbox received */
                     wkc = -EC_ERR_TYPE_PACKET_ERROR;
                     break;
                  }
               }
            }
            else
            {
               /* unexpected mailbox received */
               wkc = -EC_ERR_TYPE_PACKET_ERROR;
            }
         }
      } while (worktodo);   
   }
   
   return wkc;
}
예제 #13
0
파일: ethercatdc.c 프로젝트: hefloryd/SOEM
/**
 * Locate DC slaves, measure propagation delays.
 *
 * @param[in]  context        = context struct
 * @return boolean if slaves are found with DC
 */
boolean ecx_configdc(ecx_contextt *context)
{
    uint16 i, slaveh, parent, child;
    uint16 parenthold = 0;
    uint16 prevDCslave = 0;
    int32 ht, dt1, dt2, dt3;
    int64 hrt;
    uint8 entryport;
    int8 nlist;
    int8 plist[4];
    int32 tlist[4];
    ec_timet mastertime;
    uint64 mastertime64;

    context->slavelist[0].hasdc = FALSE;
    context->grouplist[0].hasdc = FALSE;
    ht = 0;

    ecx_BWR(context->port, 0, ECT_REG_DCTIME0, sizeof(ht), &ht, EC_TIMEOUTRET);  /* latch DCrecvTimeA of all slaves */
    mastertime = osal_current_time();
    mastertime.sec -= 946684800UL;  /* EtherCAT uses 2000-01-01 as epoch start instead of 1970-01-01 */
    mastertime64 = (((uint64)mastertime.sec * 1000000) + (uint64)mastertime.usec) * 1000;
    for (i = 1; i <= *(context->slavecount); i++)
    {
        context->slavelist[i].consumedports = context->slavelist[i].activeports;
        if (context->slavelist[i].hasdc)
        {
            if (!context->slavelist[0].hasdc)
            {
                context->slavelist[0].hasdc = TRUE;
                context->slavelist[0].DCnext = i;
                context->slavelist[i].DCprevious = 0;
                context->grouplist[0].hasdc = TRUE;
                context->grouplist[0].DCnext = i;
            }
            else
            {
                context->slavelist[prevDCslave].DCnext = i;
                context->slavelist[i].DCprevious = prevDCslave;
            }
            /* this branch has DC slave so remove parenthold */
            parenthold = 0;
            prevDCslave = i;
            slaveh = context->slavelist[i].configadr;
            (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME0, sizeof(ht), &ht, EC_TIMEOUTRET);
            context->slavelist[i].DCrtA = etohl(ht);
            /* 64bit latched DCrecvTimeA of each specific slave */
            (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCSOF, sizeof(hrt), &hrt, EC_TIMEOUTRET);
            /* use it as offset in order to set local time around 0 + mastertime */
            hrt = htoell(-etohll(hrt) + mastertime64);
            /* save it in the offset register */
            (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYSOFFSET, sizeof(hrt), &hrt, EC_TIMEOUTRET);
            (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME1, sizeof(ht), &ht, EC_TIMEOUTRET);
            context->slavelist[i].DCrtB = etohl(ht);
            (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME2, sizeof(ht), &ht, EC_TIMEOUTRET);
            context->slavelist[i].DCrtC = etohl(ht);
            (void)ecx_FPRD(context->port, slaveh, ECT_REG_DCTIME3, sizeof(ht), &ht, EC_TIMEOUTRET);
            context->slavelist[i].DCrtD = etohl(ht);

            /* make list of active ports and their time stamps */
            nlist = 0;
            if (context->slavelist[i].activeports & PORTM0)
            {
                plist[nlist] = 0;
                tlist[nlist] = context->slavelist[i].DCrtA;
                nlist++;
            }
            if (context->slavelist[i].activeports & PORTM3)
            {
                plist[nlist] = 3;
                tlist[nlist] = context->slavelist[i].DCrtD;
                nlist++;
            }
            if (context->slavelist[i].activeports & PORTM1)
            {
                plist[nlist] = 1;
                tlist[nlist] = context->slavelist[i].DCrtB;
                nlist++;
            }
            if (context->slavelist[i].activeports & PORTM2)
            {
                plist[nlist] = 2;
                tlist[nlist] = context->slavelist[i].DCrtC;
                nlist++;
            }
            /* entryport is port with the lowest timestamp */
            entryport = 0;
            if((nlist > 1) && (tlist[1] < tlist[entryport]))
            {
                entryport = 1;
            }
            if((nlist > 2) && (tlist[2] < tlist[entryport]))
            {
                entryport = 2;
            }
            if((nlist > 3) && (tlist[3] < tlist[entryport]))
            {
                entryport = 3;
            }
            entryport = plist[entryport];
            context->slavelist[i].entryport = entryport;
            /* consume entryport from activeports */
            context->slavelist[i].consumedports &= (uint8)~(1 << entryport);

            /* finding DC parent of current */
            parent = i;
            do
            {
                child = parent;
                parent = context->slavelist[parent].parent;
            }
            while (!((parent == 0) || (context->slavelist[parent].hasdc)));
            /* only calculate propagation delay if slave is not the first */
            if (parent > 0)
            {
                /* find port on parent this slave is connected to */
                context->slavelist[i].parentport = ecx_parentport(context, parent);
                if (context->slavelist[parent].topology == 1)
                {
                    context->slavelist[i].parentport = context->slavelist[parent].entryport;
                }

                dt1 = 0;
                dt2 = 0;
                /* delta time of (parentport - 1) - parentport */
                /* note: order of ports is 0 - 3 - 1 -2 */
                /* non active ports are skipped */
                dt3 = ecx_porttime(context, parent, context->slavelist[i].parentport) -
                      ecx_porttime(context, parent,
                                   ecx_prevport(context, parent, context->slavelist[i].parentport));
                /* current slave has children */
                /* those children's delays need to be subtracted */
                if (context->slavelist[i].topology > 1)
                {
                    dt1 = ecx_porttime(context, i,
                                       ecx_prevport(context, i, context->slavelist[i].entryport)) -
                          ecx_porttime(context, i, context->slavelist[i].entryport);
                }
                /* we are only interested in positive difference */
                if (dt1 > dt3) dt1 = -dt1;
                /* current slave is not the first child of parent */
                /* previous child's delays need to be added */
                if ((child - parent) > 1)
                {
                    dt2 = ecx_porttime(context, parent,
                                       ecx_prevport(context, parent, context->slavelist[i].parentport)) -
                          ecx_porttime(context, parent, context->slavelist[parent].entryport);
                }
                if (dt2 < 0) dt2 = -dt2;

                /* calculate current slave delay from delta times */
                /* assumption : forward delay equals return delay */
                context->slavelist[i].pdelay = ((dt3 - dt1) / 2) + dt2 +
                                               context->slavelist[parent].pdelay;
                ht = htoel(context->slavelist[i].pdelay);
                /* write propagation delay*/
                (void)ecx_FPWR(context->port, slaveh, ECT_REG_DCSYSDELAY, sizeof(ht), &ht, EC_TIMEOUTRET);
            }
        }
        else
        {
            context->slavelist[i].DCrtA = 0;
            context->slavelist[i].DCrtB = 0;
            context->slavelist[i].DCrtC = 0;
            context->slavelist[i].DCrtD = 0;
            parent = context->slavelist[i].parent;
            /* if non DC slave found on first position on branch hold root parent */
            if ( (parent > 0) && (context->slavelist[parent].topology > 2))
                parenthold = parent;
            /* if branch has no DC slaves consume port on root parent */
            if ( parenthold && (context->slavelist[i].topology == 1))
            {
                ecx_parentport(context, parenthold);
                parenthold = 0;
            }
        }
    }

    return context->slavelist[0].hasdc;
}
예제 #14
0
/** Map all PDOs from slaves to IOmap.
 *
 * @param[out] pIOmap	  = pointer to IOmap	
 * @return IOmap size
 */
int ec_config_map(void *pIOmap)
{
    uint16 slave, configadr;
	int Isize, Osize, BitCount, ByteCount, FMMUsize, FMMUdone;
	uint16 SMlength;
    uint8 BitPos, EndAddr;
	uint8 SMc, FMMUc;
	uint32 LogAddr = 0;
	int nSM, rval;
	ec_eepromPDOt eepPDO;

	if (ec_slavecount > 0)
	{	
		LogAddr = 0;
		BitPos = 0;

		/* find output mapping of slave and program FMMU0 */
		for (slave = 1; slave <= ec_slavecount; slave++)
        {
            configadr = ec_slave[slave].configadr;

			ec_statecheck(slave, EC_STATE_PRE_OP,  EC_TIMEOUTSTATE); //* check state change pre-op */
			
			/* if slave not found in configlist find IO mapping in slave self */
			if (!ec_slave[slave].configindex)
			{
				Isize = 0;
				Osize = 0;
				if (ec_slave[slave].mbx_proto & ECT_MBXPROT_COE) /* has CoE */
				{
					if (ec_slave[slave].CoEdetails & ECT_COEDET_SDOCA) /* has Complete Access */
					{
						/* read PDO mapping via CoE and use Complete Access */
						rval = ec_readPDOmapCA(slave, &Osize, &Isize);
					}
					else
					{
						/* read PDO mapping via CoE */
						rval = ec_readPDOmap(slave, &Osize, &Isize);
					}	
					ec_slave[slave].SM[2].SMlength = htoes((Osize + 7) / 8);
					ec_slave[slave].SM[3].SMlength = htoes((Isize + 7) / 8);
				}
				if ((!Isize && !Osize) && (ec_slave[slave].mbx_proto & ECT_MBXPROT_SOE)) /* has SoE */
				{
					/* read AT / MDT mapping via SoE */
					rval = ec_readIDNmap(slave, &Osize, &Isize);
					ec_slave[slave].SM[2].SMlength = htoes((Osize + 7) / 8);
					ec_slave[slave].SM[3].SMlength = htoes((Isize + 7) / 8);
				}
				if (!Isize && !Osize) /* find PDO mapping by SII */
				{
					Isize = ec_siiPDO (slave, &eepPDO, 0);
					for( nSM=0 ; nSM < EC_MAXSM ; nSM++ )
					{	
						if (eepPDO.SMbitsize[nSM] > 0)
						{	
							ec_slave[slave].SM[nSM].SMlength =  htoes((eepPDO.SMbitsize[nSM] + 7) / 8);
							ec_slave[slave].SMtype[nSM] = 3;
						}	
					}	
					Osize = ec_siiPDO (slave, &eepPDO, 1);
					for( nSM=0 ; nSM < EC_MAXSM ; nSM++ )
					{	
						if (eepPDO.SMbitsize[nSM] > 0)
						{	
							ec_slave[slave].SM[nSM].SMlength =  htoes((eepPDO.SMbitsize[nSM] + 7) / 8);
							ec_slave[slave].SMtype[nSM] = 2;
						}	
					}	
				}
				ec_slave[slave].Obits = Osize;
				ec_slave[slave].Ibits = Isize;
				
			}

			if (!ec_slave[slave].mbx_l && ec_slave[slave].SM[0].StartAddr)
			{
				ec_FPWR (configadr, ECT_REG_SM0, sizeof(ec_smt), &ec_slave[slave].SM[0], EC_TIMEOUTRET);
			}	
			if (!ec_slave[slave].mbx_l && ec_slave[slave].SM[1].StartAddr)
			{
				ec_FPWR (configadr, ECT_REG_SM1, sizeof(ec_smt), &ec_slave[slave].SM[1], EC_TIMEOUTRET);
			}	
			if (ec_slave[slave].SM[2].StartAddr)
			{
				/* check if SM length is zero -> clear enable flag */
				if( ec_slave[slave].SM[2].SMlength == 0) 
					ec_slave[slave].SM[2].SMflags = htoel( etohl(ec_slave[slave].SM[2].SMflags) & EC_SMENABLEMASK);
				ec_FPWR (configadr, ECT_REG_SM2, sizeof(ec_smt), &ec_slave[slave].SM[2], EC_TIMEOUTRET);
			}	
			// usleep(1000); // was needed for NETX (needs internal time after SM update)
			if (ec_slave[slave].SM[3].StartAddr)
			{
				/* check if SM length is zero -> clear enable flag */
				if( ec_slave[slave].SM[3].SMlength == 0)
					ec_slave[slave].SM[3].SMflags = htoel( etohl(ec_slave[slave].SM[3].SMflags) & EC_SMENABLEMASK);
				ec_FPWR (configadr, ECT_REG_SM3, sizeof(ec_smt), &ec_slave[slave].SM[3], EC_TIMEOUTRET);
			}	
			if (ec_slave[slave].Ibits > 7)
				ec_slave[slave].Ibytes = (ec_slave[slave].Ibits + 7) / 8;
			if (ec_slave[slave].Obits > 7)
				ec_slave[slave].Obytes = (ec_slave[slave].Obits + 7) / 8;

			FMMUc = 0;
			SMc = 0;
			BitCount = 0;
			ByteCount = 0;
			EndAddr = 0;
			FMMUsize = 0;
			FMMUdone = 0;
			/* create output mapping */
			if (ec_slave[slave].Obits)
			{
				/* search for SM that contribute to the output mapping */
				while ( (SMc < (EC_MAXSM - 1)) && (FMMUdone < ((ec_slave[slave].Obits + 7) / 8)))
				{	
					while ( (SMc < (EC_MAXSM - 1)) && (ec_slave[slave].SMtype[SMc] != 2)) SMc++;
					ec_slave[slave].FMMU[FMMUc].PhysStart = ec_slave[slave].SM[SMc].StartAddr;
					SMlength = etohs(ec_slave[slave].SM[SMc].SMlength);
					ByteCount += SMlength;
					BitCount += SMlength * 8;
					EndAddr = etohs(ec_slave[slave].SM[SMc].StartAddr) + SMlength;
					while ( (BitCount < ec_slave[slave].Obits) && (SMc < (EC_MAXSM - 1)) ) /* more SM for output */
					{
						SMc++;
						while ( (SMc < (EC_MAXSM - 1)) && (ec_slave[slave].SMtype[SMc] != 2)) SMc++;
						/* if addresses from more SM connect use one FMMU otherwise break up in mutiple FMMU */
						if ( etohs(ec_slave[slave].SM[SMc].StartAddr) > EndAddr ) break;
						SMlength = etohs(ec_slave[slave].SM[SMc].SMlength);
						ByteCount += SMlength;
						BitCount += SMlength * 8;
						EndAddr = etohs(ec_slave[slave].SM[SMc].StartAddr) + SMlength;					
					}	

					/* bit oriented slave */
					if (!ec_slave[slave].Obytes)
					{	
						ec_slave[slave].FMMU[FMMUc].LogStart = htoel(LogAddr);
						ec_slave[slave].FMMU[FMMUc].LogStartbit = BitPos;
						BitPos += ec_slave[slave].Obits - 1;
						if (BitPos > 7)
						{
							LogAddr++;
							BitPos -= 8;
						}	
						FMMUsize = LogAddr - etohl(ec_slave[slave].FMMU[FMMUc].LogStart) + 1;
						ec_slave[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
						ec_slave[slave].FMMU[FMMUc].LogEndbit = BitPos;
						BitPos ++;
						if (BitPos > 7)
						{
							LogAddr++;
							BitPos -= 8;
						}	
					}
					/* byte oriented slave */
					else
					{
						if (BitPos)
						{
							LogAddr++;
							BitPos = 0;
						}	
						ec_slave[slave].FMMU[FMMUc].LogStart = htoel(LogAddr);
						ec_slave[slave].FMMU[FMMUc].LogStartbit = BitPos;
						BitPos = 7;
						FMMUsize = ByteCount;
						if ((FMMUsize + FMMUdone)> ec_slave[slave].Obytes)
							FMMUsize = ec_slave[slave].Obytes - FMMUdone;
						LogAddr += FMMUsize;
						ec_slave[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
						ec_slave[slave].FMMU[FMMUc].LogEndbit = BitPos;
						BitPos = 0;
					}
					FMMUdone += FMMUsize;
					ec_slave[slave].FMMU[FMMUc].PhysStartBit = 0;
					ec_slave[slave].FMMU[FMMUc].FMMUtype = 2;
					ec_slave[slave].FMMU[FMMUc].FMMUactive = 1;
					/* program FMMU for output */
					ec_FPWR (configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc), sizeof(ec_fmmut), 
					         &ec_slave[slave].FMMU[FMMUc], EC_TIMEOUTRET);
					if (!ec_slave[slave].outputs)
					{	
						ec_slave[slave].outputs = pIOmap + etohl(ec_slave[slave].FMMU[FMMUc].LogStart);
						ec_slave[slave].Ostartbit = ec_slave[slave].FMMU[FMMUc].LogStartbit;
					}
					FMMUc++;
				}	
			}
        }
		ec_slave[0].outputs = pIOmap;
		if (BitPos)
		{
			LogAddr++;
			BitPos = 0;
		}	
		ec_slave[0].Obytes = LogAddr; /* store output bytes in master record */
		
		/* do input mapping of slave and program FMMUs */
		for (slave = 1; slave <= ec_slavecount; slave++)
        {
            configadr = ec_slave[slave].configadr;
			FMMUc = 1;
			if (ec_slave[slave].Obits) /* find free FMMU */
			{	
				while ( ec_slave[slave].FMMU[FMMUc].LogStart ) FMMUc++;
			}
			SMc = 0;
			BitCount = 0;
			ByteCount = 0;
			EndAddr = 0;
			FMMUsize = 0;
			FMMUdone = 0;
			/* create input mapping */
			if (ec_slave[slave].Ibits)
			{
				/* search for SM that contribute to the input mapping */
				while ( (SMc < (EC_MAXSM - 1)) && (FMMUdone < ((ec_slave[slave].Ibits + 7) / 8)))
				{	
					while ( (SMc < (EC_MAXSM - 1)) && (ec_slave[slave].SMtype[SMc] != 3)) SMc++;
					ec_slave[slave].FMMU[FMMUc].PhysStart = ec_slave[slave].SM[SMc].StartAddr;
					SMlength = etohs(ec_slave[slave].SM[SMc].SMlength);
					ByteCount += SMlength;
					BitCount += SMlength * 8;
					EndAddr = etohs(ec_slave[slave].SM[SMc].StartAddr) + SMlength;
					while ( (BitCount < ec_slave[slave].Obits) && (SMc < (EC_MAXSM - 1)) ) /* more SM for input */
					{
						SMc++;
						while ( (SMc < (EC_MAXSM - 1)) && (ec_slave[slave].SMtype[SMc] != 3)) SMc++;
						/* if addresses from more SM connect use one FMMU otherwise break up in mutiple FMMU */
						if ( etohs(ec_slave[slave].SM[SMc].StartAddr) > EndAddr ) break;
						SMlength = etohs(ec_slave[slave].SM[SMc].SMlength);
						ByteCount += SMlength;
						BitCount += SMlength * 8;
						EndAddr = etohs(ec_slave[slave].SM[SMc].StartAddr) + SMlength;					
					}	

					/* bit oriented slave */
					if (!ec_slave[slave].Ibytes)
					{	
						ec_slave[slave].FMMU[FMMUc].LogStart = htoel(LogAddr);
						ec_slave[slave].FMMU[FMMUc].LogStartbit = BitPos;
						BitPos += ec_slave[slave].Ibits - 1;
						if (BitPos > 7)
						{
							LogAddr++;
							BitPos -= 8;
						}	
						FMMUsize = LogAddr - etohl(ec_slave[slave].FMMU[FMMUc].LogStart) + 1;
						ec_slave[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
						ec_slave[slave].FMMU[FMMUc].LogEndbit = BitPos;
						BitPos ++;
						if (BitPos > 7)
						{
							LogAddr++;
							BitPos -= 8;
						}	
					}
					/* byte oriented slave */
					else
					{
						if (BitPos)
						{
							LogAddr++;
							BitPos = 0;
						}	
						ec_slave[slave].FMMU[FMMUc].LogStart = htoel(LogAddr);
						ec_slave[slave].FMMU[FMMUc].LogStartbit = BitPos;
						BitPos = 7;
						FMMUsize = ByteCount;
						if ((FMMUsize + FMMUdone)> ec_slave[slave].Ibytes)
							FMMUsize = ec_slave[slave].Ibytes - FMMUdone;
						LogAddr += FMMUsize;
						ec_slave[slave].FMMU[FMMUc].LogLength = htoes(FMMUsize);
						ec_slave[slave].FMMU[FMMUc].LogEndbit = BitPos;
						BitPos = 0;
					}
					FMMUdone += FMMUsize;
					if (ec_slave[slave].FMMU[FMMUc].LogLength)
					{	
						ec_slave[slave].FMMU[FMMUc].PhysStartBit = 0;
						ec_slave[slave].FMMU[FMMUc].FMMUtype = 1;
						ec_slave[slave].FMMU[FMMUc].FMMUactive = 1;
						/* program FMMU for input */
						ec_FPWR (configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc), sizeof(ec_fmmut), 
						         &ec_slave[slave].FMMU[FMMUc], EC_TIMEOUTRET);
					}	
					if (!ec_slave[slave].inputs)
					{	
						ec_slave[slave].inputs = pIOmap + etohl(ec_slave[slave].FMMU[FMMUc].LogStart);
						ec_slave[slave].Istartbit = ec_slave[slave].FMMU[FMMUc].LogStartbit;
					}
					FMMUc++;
				}	
			}

			ec_eeprom2pdi(slave); /* set Eeprom control to PDI */			
			ec_FPWRw(configadr, ECT_REG_ALCTL, htoes(EC_STATE_SAFE_OP) , EC_TIMEOUTRET); /* set safeop status */
						
		}
		ec_slave[0].inputs = pIOmap + ec_slave[0].Obytes;
		if (BitPos)
		{
			LogAddr++;
			BitPos = 0;
		}	
		ec_slave[0].Ibytes = LogAddr - ec_slave[0].Obytes; /* store input bytes in master record */
		
	}
	return LogAddr;
}	
예제 #15
0
/** Enumerate and init all slaves.
 *
 * @param[in] usetable	  = TRUE when using configtable to init slaves, FALSE otherwise
 * @return Workcounter of slave discover datagram = number of slaves found
 */
int ec_config_init(uint8 usetable)
{
    uint16 w, slave, ADPh, configadr, mbx_wo, mbx_ro, mbx_l, ssigen;
    uint16 topology, estat;
    int16 topoc, slavec;
    uint8 b,h;
	uint8 zbuf[64];
	uint8 SMc;
	uint32 eedat;
	int wkc, cindex, nSM;

    ec_slavecount = 0;
	/* clean ec_slave array */
	memset(&ec_slave, 0x00, sizeof(ec_slave));
	memset(&zbuf, 0x00, sizeof(zbuf));
    w = 0x0000;
    wkc = ec_BRD(0x0000, ECT_REG_TYPE, sizeof(w), &w, EC_TIMEOUTSAFE);		/* detect number of slaves */

    if (wkc > 0)
    {
        ec_slavecount = wkc;
        b = 0x00;
        ec_BWR(0x0000, ECT_REG_DLPORT, sizeof(b), &b, EC_TIMEOUTRET);		/* deact loop manual */
        w = htoes(0x0004);
        ec_BWR(0x0000, ECT_REG_IRQMASK, sizeof(w), &w, EC_TIMEOUTRET);		/* set IRQ mask */
        ec_BWR(0x0000, ECT_REG_RXERR, 8, &zbuf, EC_TIMEOUTRET);  			/* reset CRC counters */
        ec_BWR(0x0000, ECT_REG_FMMU0, 16 * 3, &zbuf, EC_TIMEOUTRET);		/* reset FMMU's */
        ec_BWR(0x0000, ECT_REG_SM0, 8 * 4, &zbuf, EC_TIMEOUTRET);			/* reset SyncM */
        ec_BWR(0x0000, ECT_REG_DCSYSTIME, 4, &zbuf, EC_TIMEOUTRET); 		/* reset system time+ofs */
        w = htoes(0x1000);
        ec_BWR(0x0000, ECT_REG_DCSPEEDCNT, sizeof(w), &w, EC_TIMEOUTRET);   /* DC speedstart */
        w = htoes(0x0c00);
        ec_BWR(0x0000, ECT_REG_DCTIMEFILT, sizeof(w), &w, EC_TIMEOUTRET);   /* DC filt expr */
        b = 0x00;
        ec_BWR(0x0000, ECT_REG_DLALIAS, sizeof(b), &b, EC_TIMEOUTRET);		/* Ignore Alias register */
        b = EC_STATE_INIT | EC_STATE_ACK;
        ec_BWR(0x0000, ECT_REG_ALCTL, sizeof(b), &b, EC_TIMEOUTRET);		/* Reset all slaves to Init */
		b = 2;
		ec_BWR(0x0000, ECT_REG_EEPCFG, sizeof(b), &b , EC_TIMEOUTRET); 		/* force Eeprom from PDI */
		b = 0;
		ec_BWR(0x0000, ECT_REG_EEPCFG, sizeof(b), &b , EC_TIMEOUTRET); 		/* set Eeprom to master */
		
        for (slave = 1; slave <= ec_slavecount; slave++)
        {
            ADPh = (uint16)(1 - slave);
            ec_slave[slave].Itype = etohs(ec_APRDw(ADPh, ECT_REG_PDICTL, EC_TIMEOUTRET)); /* read interface type of slave */
			/* a node offset is used to improve readibility of network frames */
			/* this has no impact on the number of addressable slaves (auto wrap around) */
            ec_APWRw(ADPh, ECT_REG_STADR, htoes(slave + EC_NODEOFFSET) , EC_TIMEOUTRET); /* set node address of slave */
            if (slave == 1) 
			{
				b = 1; /* kill non ecat frames for first slave */
			}
			else 
			{
				b = 0; /* pass all frames for following slaves */
			}
            ec_APWRw(ADPh, ECT_REG_DLCTL, htoes(b), EC_TIMEOUTRET); /* set non ecat frame behaviour */
            configadr = etohs(ec_APRDw(ADPh, ECT_REG_STADR, EC_TIMEOUTRET));
            ec_slave[slave].configadr = configadr;
		    ec_FPRD(configadr, ECT_REG_EEPSTAT, sizeof(estat), &estat, EC_TIMEOUTRET);
			estat = etohs(estat);
			if ((estat & (1 << 6))) /* check if slave can read 8 byte chunks */
			{
				ec_slave[slave].eep_8byte = 1;
			}
            ec_readeeprom1(slave, ECT_SII_MANUF); /* Manuf */
        }
		for (slave = 1; slave <= ec_slavecount; slave++)
        {
            ec_slave[slave].eep_man = etohl(ec_readeeprom2(slave, EC_TIMEOUTEEP)); /* Manuf */
            ec_readeeprom1(slave, ECT_SII_ID); /* ID */
        }
        for (slave = 1; slave <= ec_slavecount; slave++)
        {
            ec_slave[slave].eep_id = etohl(ec_readeeprom2(slave, EC_TIMEOUTEEP)); /* ID */
            ec_readeeprom1(slave, ECT_SII_REV); /* revision */
        }
        for (slave = 1; slave <= ec_slavecount; slave++)
        {
            ec_slave[slave].eep_rev = etohl(ec_readeeprom2(slave, EC_TIMEOUTEEP)); /* revision */
            ec_readeeprom1(slave, ECT_SII_RXMBXADR); /* write mailbox address + mailboxsize */
        }
        for (slave = 1; slave <= ec_slavecount; slave++)
        {
            eedat = etohl(ec_readeeprom2(slave, EC_TIMEOUTEEP)); /* write mailbox address and mailboxsize */
            ec_slave[slave].mbx_wo = (uint16)LO_WORD(eedat);
            ec_slave[slave].mbx_l = (uint16)HI_WORD(eedat);
			if (ec_slave[slave].mbx_l > 0) 
			{
	            ec_readeeprom1(slave, ECT_SII_TXMBXADR); /* read mailbox offset */
			}
        }
        for (slave = 1; slave <= ec_slavecount; slave++)
        {
			if (ec_slave[slave].mbx_l > 0) 
			{
	            ec_slave[slave].mbx_ro = (uint16)etohl(ec_readeeprom2(slave, EC_TIMEOUTEEP)); /* read mailbox offset */
			}
            configadr = ec_slave[slave].configadr;
            mbx_ro = ec_slave[slave].mbx_ro;
            mbx_wo = ec_slave[slave].mbx_wo;
            mbx_l = ec_slave[slave].mbx_l;
            if ((etohs(ec_FPRDw(configadr, ECT_REG_ESCSUP, EC_TIMEOUTRET)) & 0x04) > 0)  /* Support DC? */
            {
                ec_slave[slave].hasdc = TRUE;
            }
            else
            {
                ec_slave[slave].hasdc = FALSE;
            }
            topology = etohs(ec_FPRDw(configadr, ECT_REG_DLSTAT, EC_TIMEOUTRET)); /* extract topology from DL status */
			h = 0; 
			b = 0;
            if ((topology & 0x0300) == 0x0200) /* port0 open and communication established */
            {
                h++;
				b |= 0x01;
            }
            if ((topology & 0x0c00) == 0x0800) /* port1 open and communication established */
            {
                h++;
				b |= 0x02;
            }
            if ((topology & 0x3000) == 0x2000) /* port2 open and communication established */
            {
                h++;
				b |= 0x04;
            }
            if ((topology & 0xc000) == 0x8000) /* port3 open and communication established */
            {
                h++;
				b |= 0x08;
            }
            /* ptype = Physical type*/
            ec_slave[slave].ptype = LO_BYTE(etohs(ec_FPRDw(configadr, ECT_REG_PORTDES, EC_TIMEOUTRET)));
            ec_slave[slave].topology = h;
			ec_slave[slave].activeports = b;
			/* 0=no links, not possible             */
            /* 1=1 link  , end of line              */
            /* 2=2 links , one before and one after */
            /* 3=3 links , split point              */
            /* 4=4 links , cross point              */
            /* search for parent */
            ec_slave[slave].parent = 0; /* parent is master */
            if (slave > 1)
            {
                topoc = 0; 
                slavec = slave - 1;
                do
                {
		            topology = ec_slave[slavec].topology;
                    if (topology == 1)
                    {
                        topoc--; /* endpoint found */
                    }
                    if (topology == 3)
                    {
                        topoc++; /* split found */
                    }
                    if (topology == 4)
                    {
                        topoc+=2; /* cross found */
                    }
                    if (((topoc >= 0) && (topology > 1)) ||
					    (slavec == 1)) /* parent found */
                    {
                        ec_slave[slave].parent = slavec;
                        slavec = 1;
                    }
					slavec--;
                }
                while (slavec > 0);
            }

            w = ec_statecheck(slave, EC_STATE_INIT,  EC_TIMEOUTSTATE); //* check state change Init */
	
			/* set default mailbox configuration if slave has mailbox */
			if (ec_slave[slave].mbx_l>0)
			{	
				ec_slave[slave].SMtype[0] = 0;
				ec_slave[slave].SMtype[1] = 1;
				ec_slave[slave].SMtype[2] = 2;
				ec_slave[slave].SMtype[3] = 3;
				ec_slave[slave].SM[0].StartAddr = htoes(ec_slave[slave].mbx_wo);
				ec_slave[slave].SM[0].SMlength = htoes(ec_slave[slave].mbx_l);
				ec_slave[slave].SM[0].SMflags = htoel(EC_DEFAULTMBXSM0);
				ec_slave[slave].SM[1].StartAddr = htoes(ec_slave[slave].mbx_ro);
				ec_slave[slave].SM[1].SMlength = htoes(ec_slave[slave].mbx_l);
				ec_slave[slave].SM[1].SMflags = htoel(EC_DEFAULTMBXSM1);
				ec_slave[slave].mbx_proto = ec_readeeprom (slave, ECT_SII_MBXPROTO, EC_TIMEOUTEEP);
			}	
			cindex = 0;
			/* use configuration table ? */
			if (usetable)
			{
				cindex = ec_findconfig( ec_slave[slave].eep_man, ec_slave[slave].eep_id );
				ec_slave[slave].configindex= cindex;
			}
			/* slave found in configuration table ? */
			if (cindex)
			{
				ec_slave[slave].Dtype = ec_configlist[cindex].Dtype;				
				strcpy(	ec_slave[slave].name ,ec_configlist[cindex].name);
				ec_slave[slave].Ibits = ec_configlist[cindex].Ibits;
				ec_slave[slave].Obits = ec_configlist[cindex].Obits;
				if (ec_slave[slave].Obits)
				{	
					ec_slave[slave].FMMU0func = 1;
				}	
				if (ec_slave[slave].Ibits)
				{	
					ec_slave[slave].FMMU1func = 2;
				}	
				ec_slave[slave].FMMU[0].FMMUactive = ec_configlist[cindex].FM0ac;
				ec_slave[slave].FMMU[1].FMMUactive = ec_configlist[cindex].FM1ac;
				ec_slave[slave].SM[2].StartAddr = htoes(ec_configlist[cindex].SM2a);
				ec_slave[slave].SM[2].SMflags = htoel(ec_configlist[cindex].SM2f);
				/* simple (no mailbox) output slave found ? */
				if (ec_slave[slave].Obits && !ec_slave[slave].SM[2].StartAddr)
				{
					ec_slave[slave].SM[0].StartAddr = htoes(0x0f00);
					ec_slave[slave].SM[0].SMlength = htoes((ec_slave[slave].Obits + 7) / 8);
					ec_slave[slave].SM[0].SMflags = htoel(EC_DEFAULTDOSM0);			
					ec_slave[slave].FMMU[0].FMMUactive = 1;
					ec_slave[slave].FMMU[0].FMMUtype = 2;
					ec_slave[slave].SMtype[0] = 2;
				}
				/* complex output slave */
				else
				{
					ec_slave[slave].SM[2].SMlength = htoes((ec_slave[slave].Obits + 7) / 8);
					ec_slave[slave].SMtype[2] = 2;
				}	
				ec_slave[slave].SM[3].StartAddr = htoes(ec_configlist[cindex].SM3a);
				ec_slave[slave].SM[3].SMflags = htoel(ec_configlist[cindex].SM3f);
				/* simple (no mailbox) input slave found ? */
				if (ec_slave[slave].Ibits && !ec_slave[slave].SM[3].StartAddr)
				{
					ec_slave[slave].SM[1].StartAddr = htoes(0x1000);
					ec_slave[slave].SM[1].SMlength = htoes((ec_slave[slave].Ibits + 7) / 8);
					ec_slave[slave].SM[1].SMflags = htoel(0x00000000);			
					ec_slave[slave].FMMU[1].FMMUactive = 1;
					ec_slave[slave].FMMU[1].FMMUtype = 1;
					ec_slave[slave].SMtype[1] = 3;
				}
				/* complex input slave */
				else
				{
					ec_slave[slave].SM[3].SMlength = htoes((ec_slave[slave].Ibits + 7) / 8);
					ec_slave[slave].SMtype[3] = 3;
				}	
			}
			/* slave not in configuration table, find out via SII */
			else
			{
				ssigen = ec_siifind(slave, ECT_SII_GENERAL);
				/* SII general section */
				if (ssigen)
                {
					ec_slave[slave].CoEdetails = ec_siigetbyte(slave, ssigen + 0x07);
					ec_slave[slave].FoEdetails = ec_siigetbyte(slave, ssigen + 0x08);
					ec_slave[slave].EoEdetails = ec_siigetbyte(slave, ssigen + 0x09);
					ec_slave[slave].SoEdetails = ec_siigetbyte(slave, ssigen + 0x0a);
					if((ec_siigetbyte(slave, ssigen + 0x0d) & 0x02) > 0)
					{
						ec_slave[slave].blockLRW = 1;
						ec_slave[0].blockLRW++;						
					}	
					ec_slave[slave].Ebuscurrent = ec_siigetbyte(slave, ssigen + 0x0e);
					ec_slave[slave].Ebuscurrent += ec_siigetbyte(slave, ssigen + 0x0f) << 8;
					ec_slave[0].Ebuscurrent += ec_slave[slave].Ebuscurrent;
                }
				/* SII strings section */
				if (ec_siifind(slave, ECT_SII_STRING) > 0)
                {
                    ec_siistring(ec_slave[slave].name, slave, 1);
                }
				/* no name for slave found, use constructed name */
                else
                {
                    sprintf(ec_slave[slave].name, "? M:%8.8x I:%8.8x",
                    (unsigned int)ec_slave[slave].eep_man, (unsigned int)ec_slave[slave].eep_id);
                }
				/* SII SM section */
				nSM = ec_siiSM (slave,&ec_SM);
				if (nSM>0)
				{	
					ec_slave[slave].SM[0].StartAddr = htoes(ec_SM.PhStart);
					ec_slave[slave].SM[0].SMlength = htoes(ec_SM.Plength);
					ec_slave[slave].SM[0].SMflags = htoel((ec_SM.Creg) + (ec_SM.Activate << 16));
					SMc = 1;
					while ((SMc < EC_MAXSM) &&  ec_siiSMnext(slave, &ec_SM, SMc))
					{
						ec_slave[slave].SM[SMc].StartAddr = htoes(ec_SM.PhStart);
						ec_slave[slave].SM[SMc].SMlength = htoes(ec_SM.Plength);
						ec_slave[slave].SM[SMc].SMflags = htoel((ec_SM.Creg) + (ec_SM.Activate << 16));
						SMc++;
					}	
				}	
				/* SII FMMU section */
                if (ec_siiFMMU(slave, &ec_FMMU))
				{
					if (ec_FMMU.FMMU0 !=0xff) 
						ec_slave[slave].FMMU0func = ec_FMMU.FMMU0;
					if (ec_FMMU.FMMU1 !=0xff) 
						ec_slave[slave].FMMU1func = ec_FMMU.FMMU1;
					if (ec_FMMU.FMMU2 !=0xff) 
						ec_slave[slave].FMMU2func = ec_FMMU.FMMU2;
					if (ec_FMMU.FMMU3 !=0xff) 
						ec_slave[slave].FMMU3func = ec_FMMU.FMMU3;
				}	
			}	

			if (ec_slave[slave].mbx_l > 0)
			{
				if (ec_slave[slave].SM[0].StartAddr == 0x0000) /* should never happen */
				{
					ec_slave[slave].SM[0].StartAddr = htoes(0x1000);
					ec_slave[slave].SM[0].SMlength = htoes(0x0080);
					ec_slave[slave].SM[0].SMflags = htoel(EC_DEFAULTMBXSM0);
					ec_slave[slave].SMtype[0] = 0;					
				}			
				if (ec_slave[slave].SM[1].StartAddr == 0x0000) /* should never happen */
				{
					ec_slave[slave].SM[1].StartAddr = htoes(0x1080);
					ec_slave[slave].SM[1].SMlength = htoes(0x0080);
					ec_slave[slave].SM[1].SMflags = htoel(EC_DEFAULTMBXSM1);
					ec_slave[slave].SMtype[1] = 1;
				}			
				/* program SM0 mailbox in for slave */
				ec_FPWR (configadr, ECT_REG_SM0, sizeof(ec_smt), &ec_slave[slave].SM[0], EC_TIMEOUTRET);
				/* program SM1 mailbox out for slave */
				// usleep(1000); // was needed for NETX (needs internal time after SM update)
				ec_FPWR (configadr, ECT_REG_SM1, sizeof(ec_smt), &ec_slave[slave].SM[1], EC_TIMEOUTRET);
			}	
			ec_FPWRw(configadr, ECT_REG_ALCTL, htoes(EC_STATE_PRE_OP | EC_STATE_ACK) , EC_TIMEOUTRET); /* set preop status */
		}
	}	
    return wkc;
}