Hello again,

I'm continuing my work on a proof of concept application using the IgH EtherCAT master however I'm having more problems. Specifically I'm seeing warnings and errors when trying to setup a Beckhoff EL2252 module:
====================================================
Dec 15 08:49:31 lyot kernel: [90434.144520] EtherCAT ERROR 0-2: Slave does not support CoE! Dec 15 08:49:31 lyot kernel: [90434.244602] EtherCAT ERROR 0-2: Failed to read number of mapped PDO entries. Dec 15 08:49:31 lyot kernel: [90434.244605] EtherCAT WARNING 0-2: Failed to read PDO entries for PDO 0x1604.
====================================================
I see the above errors both when using my code (attached but not yet functioning) as well as using a working example program that I found on the mailing list [1] (much thanks Philippe).

WRT the warnings/errors above:
Do I need to be concerned about the errors/warnings that I see in the log?
If they aren't of concern is there any way to silence them?

Thanks in advance


[1] http://lists.etherlab.org/pipermail/etherlab-users/2013/002134.html

--
-john

To be or not to be, that is the question
                2b || !2b
(0b10)*(0b1100010) || !(0b10)*(0b1100010)
        0b11000100 || !0b11000100
        0b11000100 ||  0b00111011
               0b11111111
255, that is the answer.

#include <sstream>
#include <bitset>
#include "OutputModule.h"

OutputModule::OutputModule(uint16_t position) : 
    EtherCatSlave(OutputModule::BECKHOFF_ID, OutputModule::EL2252_ID, 
    position) {
  int i = 0;

  pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x1d09, 0x81, 
      &offsetActivate, NULL};

  pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x1d09, 0x90, 
      &offsetStartTime, NULL};

  pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x7000, 0x01, 
      &offsetOutput[0], &bitPosOutput[0]};

  pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x7000, 0x02, 
      &offsetTriState[0], &bitPosTriState[0]};

  pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x7010, 0x01, 
      &offsetOutput[1], &bitPosOutput[1]};

  pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x7010, 0x02, 
      &offsetTriState[1], &bitPosTriState[1]};

  //pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x1d09, 0x10, 
      //&offsetSysTime, NULL};

  //pdoRegs[i++] = { 0, position, BECKHOFF_ID, EL2252_ID, 0x1d09, 0x11, 
      //&offsetFeedback, NULL};

  pdoRegs[i++] = { };

 state = IDLE;
}

const ec_sync_info_t* OutputModule::getSyncs() const {
  return syncs;
}

const ec_pdo_entry_reg_t* OutputModule::getPdoEntryRegs() const {
  return pdoRegs;
}

void OutputModule::readProcessData(uint8_t* processData) { }

void OutputModule::writeProcessData(uint8_t* processData) {
  switch (state) {
    case IDLE: 
      break;
    case WRITE_READY:
      EC_WRITE_U64(processData + offsetStartTime, time);
      for (int i = 0; i < 2; i++) {
        EC_WRITE_BIT(processData + offsetOutput[i], offsetOutput[i], output[i]);
        EC_WRITE_BIT(processData + offsetTriState[i], offsetTriState[i], 0);
      }
      EC_WRITE_U8(processData + offsetActivate, 0);
      std::cout << "State transitioned from WRITE_READY --> WRITE_STARTED";
      std::cout << std::endl;
      state = WRITE_STARTED;
      break;
    case WRITE_STARTED:
      std::cout << "State transitioned from WRITE_STARTED --> IDLE";
      std::cout << std::endl;
      EC_WRITE_U8(processData + offsetActivate, 3);
      state = IDLE;
      break;
  }
}

void OutputModule::schedule(uint64_t startTime, bool output0, bool output1) {
  std::cout << "@ " << startTime << " El2252[0] will become " << output0;
  std::cout << " and El2252[1] will become " << output1 << std::endl;
  this->startTime = startTime;
  this->output[0] = output0;
  this->output[1] = output1;
  this->state = WRITE_READY;
}

OutputModule::~OutputModule() { }

const ec_pdo_entry_info_t OutputModule::pdoEntries[] = {
  {0x1d09, 0x81, 8}, /* Activate */
  {0x1d09, 0x90, 64}, /* StartTime */
  {0x7000, 0x01, 1}, /* Output */
  {0x7000, 0x02, 1}, /* TriState */
  {0x7010, 0x01, 1}, /* Output */
  {0x7010, 0x02, 1}, /* TriState */
  {0x0000, 0x00, 4}, /* Reserved */
  //{0x1d09, 0x10, 64}, /* SysTime */
  //{0x1d09, 0x11,  8}, /* Feedback */
};

const ec_pdo_info_t OutputModule::pdos[] = {

/* from original slaves.h */
  {0x1602, 1, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 0)}, //Activate
  {0x1603, 1, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 1)}, //StartTime
  {0x1600, 2, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 2)}, //Channel 1
  {0x1601, 3, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 4)}, //Channel 2
  {0x1604, 0, NULL}, //Reserved
/*
  {0x1602, 0, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 0)}, //Activate
  {0x1603, 0, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 1)}, //StartTime
  {0x1600, 0, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 2)}, //Channel 1
  {0x1601, 0, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 4)}, //Channel 2
  {0x1604, 0, NULL}, //Reserved
*/

/* from mailing list slaves.h
  {0x1602, 1, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 0)}, //Activate
  {0x1603, 1, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 1)}, //StartTime
  {0x1600, 2, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 2)}, //Channel 1
  {0x1601, 3, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 4)}, //Channel 2
  {0x1604, 0, NULL}, //Reserved
  {0x1a00, 1, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 7)}, //SysTime
  {0x1a01, 1, const_cast<ec_pdo_entry_info_t*>(pdoEntries + 8)}, //Feedback
 */
};

const ec_sync_info_t OutputModule::syncs[] = {
  /* from original slaves.h */
    {0, EC_DIR_INPUT,  1, const_cast<ec_pdo_info_t*>(pdos + 0), EC_WD_DISABLE},
    {1, EC_DIR_INPUT,  1, const_cast<ec_pdo_info_t*>(pdos + 1), EC_WD_DISABLE},
    {2, EC_DIR_OUTPUT, 3, const_cast<ec_pdo_info_t*>(pdos + 2), EC_WD_ENABLE},
    {3, EC_DIR_INPUT,  0, NULL, EC_WD_DISABLE},
    {4, EC_DIR_INPUT,  0, NULL, EC_WD_DISABLE},
    {0xff}

  /* from mailing list slaves.h 
  {0, EC_DIR_OUTPUT, 1, const_cast<ec_pdo_info_t*>(pdos + 0), EC_WD_DISABLE},
  {1, EC_DIR_OUTPUT, 1, const_cast<ec_pdo_info_t*>(pdos + 1), EC_WD_DISABLE},
  {2, EC_DIR_OUTPUT, 2, const_cast<ec_pdo_info_t*>(pdos + 2), EC_WD_ENABLE},
  {3, EC_DIR_INPUT,  1, const_cast<ec_pdo_info_t*>(pdos + 4), EC_WD_DISABLE},
  {4, EC_DIR_INPUT,  1, const_cast<ec_pdo_info_t*>(pdos + 5), EC_WD_DISABLE},
  {4, EC_DIR_INPUT,  1, const_cast<ec_pdo_info_t*>(pdos + 6), EC_WD_DISABLE},
  {0xff}
  */
};

std::string OutputModule::toString() const {
  std::stringstream os;
  for (int i = 0; i < 2; i++) {
    if (0 == i) os << "el2252 ";
    else os << "       ";
    os << i << " : ";
    //os << "in=" << input[i] ? std::string("true"): std::string("false");
    //std::bitset<8> statusBits(status[i]);
    //os << "\tstatus=" << statusBits;
    //os << "\tnegLatch=" << negLatch[i];
    //os << "\tposLatch=" << posLatch[i];
    if (i == 0) os << std::endl;
  }
  return os.str();
}

void OutputModule::printPdoEntryInfo() const {
  std::cout << "========== output module ==========" << std::endl;
  std::cout << "offsetActivate: " << offsetActivate << std::endl;
  std::cout << "offsetStartTime: " << offsetStartTime << std::endl;
  for (int i = 0; i < 2; i++) {
    std::cout << "offsetOutput["<<i<<"]: " << offsetOutput[i] << std::endl;
    std::cout << "bitPosOutput["<<i<<"]: " << bitPosOutput[i] << std::endl;
    std::cout << "offsetTriState["<<i<<"]: " << offsetTriState[i] << std::endl;
    std::cout << "bitPosTriState["<<i<<"]: " << bitPosTriState[i] << std::endl;
  }
  for (int i = 0; i < 2; i++) {
  }
  //for (int i = 0; i < 2; i++) 
  // std::cout << "offsetPosLatch["<<i<<"]: " << offsetPosLatch[i] << std::endl;
  std::cout << "===================================" << std::endl;
}

std::ostream& operator<<(std::ostream & os, OutputModule& x) {
  os << x.toString();
  return os;
}



#include <iostream>
#include <chrono>
#include <thread>

#include "EtherCat.h"
#include "Timer.h"

#define BECKHOFF 0x00000002
      
EtherCat::EtherCat(const unsigned short& masterNum) {
  master = ecrt_request_master(masterNum);
  if (NULL == master) {
    std::cerr << "ERROR:\tFailed to obtain master" << std::endl;
    exit(-1);
  } else {
    std::cout << "OK:\tMaster obtained" << std::endl;
  }

  domain = ecrt_master_create_domain(master);
  if (NULL == domain) {
    std::cerr << "ERROR:\tFailed to obtain domain" << std::endl;
    exit(-1);
  } else {
    std::cout << "OK:\tDomain obtained" << std::endl;
  }
}

EtherCat::~EtherCat() {
}

ec_master_t* EtherCat::getMaster() {
  return master;
}

ec_domain_t* EtherCat::getDomain() {
  return domain;
}

void EtherCat::start(void (*f)(EtherCat* ec), const unsigned int& micros) {
  unsigned int error = ecrt_master_activate(master);
  if (error) {
    std::cerr << "ERROR:\tFailed to activate master" << std::endl;
    exit(-1);
  } else std::cout << "OK:\tMaster activated" << std::endl;

  auto delayTime = std::chrono::microseconds(micros);
  auto nextTick = std::chrono::high_resolution_clock::now() + delayTime;

  Timer timer = Timer();
  while (!done) {
    ecrt_master_receive(getMaster());
    ecrt_domain_process(getDomain());
    uint8_t* pd = getProcessData();
    for (auto &slaveEntry: slaves) 
      slaveEntry.second->readProcessData(pd);
     
    f(this);
    for (auto &slaveEntry: slaves) 
      slaveEntry.second->writeProcessData(pd);

    ecrt_domain_queue(getDomain());
    ecrt_master_send(getMaster());

    std::this_thread::sleep_until(nextTick);
    timer.tick();
    nextTick += delayTime;
  }
  timer.printStats();

  ecrt_master_deactivate(master);
  std::cout << "OK:\tMaster deactivated" << std::endl;
}

void EtherCat::stop() {
  done = true;
} 

void EtherCat::configureSlave(const std::string& name, 
    EtherCatSlave& slave) {
  std::cout << "DEBUG:\tPreparing to configure slave '" << name;
  auto vid = slave.getVendorId();
  auto pid = slave.getProductId();
  auto pos = slave.getPositionId();
  std::cout << "' in position " << pos << std::endl;
  ec_slave_config_t* cfg = ecrt_master_slave_config(master, 0, pos, vid, pid);
  if (NULL == cfg) {
    std::cerr << "ERROR:\tFailed to obtain slave config " << name << std::endl;
    exit(-1);
  } else {
    std::cout << "OK:\tConfig obtained for slave '" << name << "'" << std::endl;
    slaveCfgs[name] = cfg;
  }

  {
    ec_slave_config_state_t state;
    ecrt_slave_config_state(cfg, &state);
    std::string opState;
    switch (state.al_state) {
      case 1: opState = "INITIALISED";
      case 2: opState = "PRE-OPERATIONAL";
      case 4: opState = "SAFE-OPERATIONAL";
      case 8: opState = "OPERATIONAL";
    }
    std::cout << "\tstate is " << opState <<  std::endl;
    //std::cout << "\t\t\tconfig obtained" <<  std::endl;
  }

  int error;
  
  error = ecrt_slave_config_pdos(cfg, EC_END, slave.getSyncs());
  if (error) {
    std::cerr << "ERROR:\tFailed to configure slave PDOs" << std::endl;
    exit(-1);
  } else {
    std::cout << "OK:\tSlave '" << name << "' pdos configured" << std::endl;
  }
  
  auto pdos = slave.getPdoEntryRegs();
  error = ecrt_domain_reg_pdo_entry_list(domain, pdos);
  if (error) {
    std::cerr << "ERROR:\tFailed to register PDOs with domain";
    std::cerr << " Error code: " << error << std::endl;
    exit(-1);
  } else {
    std::cout << "OK:\tPDOs registered with domain" << std::endl;
  }
  slaves[name] = &slave;
  slave.printPdoEntryInfo();
}

EtherCatSlave* EtherCat::getSlave(const std::string& name) {
  return slaves[name];
}

uint8_t* EtherCat::getProcessData() {
  return ecrt_domain_data(domain);
}



#include <unistd.h>
#include <signal.h>
#include <iostream>
#include <bitset>
#include <chrono>
#include <thread>
#include <string.h>

#include "ecrt.h"
#include "EtherCat.h"
#include "InputModule.h"
#include "OutputModule.h"

static EtherCat* ec;

static void checkMasterStatus(ec_master_t* master);
static void checkDomainStatus(ec_domain_t* domain);
static void doCyclicTask(EtherCat* ec);
static void term(int sigNum);

static const std::string INPUT_MODULE = "input";
static const std::string OUTPUT_MODULE = "output";

//unsigned int micros = 5000000; //  5   s  ==>   0.2 Hz
//unsigned int micros = 500000;  //  0.5 s  ==>   2   Hz
  unsigned int micros = 50000;   // 50  ms  ==>  20   Hz
//unsigned int micros = 5000;    //  5  ms  ==> 200   Hz
//unsigned int micros = 500;     //  0.5ms  ==>   2   KHz

static InputModule inputModule(1);
static OutputModule outputModule(2);


int main(int argc, char** argv) {
  std::cout << "Starting main..." << std::endl;
  //sleep(5);

  //EtherCat* ec = new EtherCat();
  ec = new EtherCat();

  ec_master_t* master = ec->getMaster();
  ec_domain_t* domain = ec->getDomain();

  //InputModule inputModule = InputModule(1);
  //OutputModule outputModule = OutputModule(2);
  ec->configureSlave(INPUT_MODULE, inputModule);
  ec->configureSlave(OUTPUT_MODULE, outputModule);

  checkMasterStatus(master);
  checkDomainStatus(domain);

  signal(SIGABRT, &term);
  signal(SIGTERM, &term);
  signal(SIGINT, &term);

  ec->start(doCyclicTask, micros);
  // stop will from from a ctrl+c signal

  delete ec;
  ec = NULL;

  std::cout << "Leaving main..." << std::endl;
  return 0;
}

static void doBlink();
static void doPrintInputInfo();
static void periodic();

static void doCyclicTask(EtherCat* ec) {
  doBlink();
  //doPrintInputInfo();
  //periodic();
}

static void periodic() {
  static uint64_t counter = 0;
  static unsigned int x = (10 * 1000 * 1000) / micros; 
  
  if (counter++ % x == 0) {
    std::cout << inputModule.toString() << std::endl;
  }
}

static void doBlink() {
  static bool lastInput[2] =  {false, false};
  static uint64_t lastPosLatch[2] =  {0, 0};
  static unsigned int blink = false;
  unsigned short channel = 1;
  bool input1 = inputModule.getInput(channel);
  if (input1 && (input1 != lastInput[channel])) {
    uint64_t time = inputModule.getPosLatch(channel);
    std::cout << "button press detected @ ";
    std::cout << time << std::endl;
    // add 1 second
    time += 1000000000;
    outputModule.schedule(time, blink, !blink);
    blink = !blink;
  }
  for (unsigned short i = 0; i < 2; i++) {
    lastInput[i] = inputModule.getInput(i);
    lastPosLatch[i] = inputModule.getPosLatch(i);
  }
}

static void doPrintInputInfo() {
  static bool lastInput[2] =  {false, false};
  static uint64_t lastPosLatch[2] =  {0, 0};
  for (unsigned short i = 0; i < 2; i++) {
    bool input = inputModule.getInput(i);
    if (input != lastInput[i]) 
      std::cout << inputModule.toString() << std::endl;

    lastInput[i] = inputModule.getInput(i);
    lastPosLatch[i] = inputModule.getPosLatch(i);
  }
}

static void term(int signum) {
  std::cerr << "Received sig: " << signum << std::endl;
  if (NULL != ec) ec->stop();
}

static void checkMasterStatus(ec_master_t* master) {
  ec_master_state_t ms;
  ecrt_master_state(master, &ms);
  std::bitset<4> states(ms.al_states);
  std::cout << "Master:\tlink is " << (ms.link_up ? "up" : "down");
  std::cout << " with " << ms.slaves_responding << " slave(s)." << std::endl;
  std::cout << "       \tapplication layer states: 0b" << states << std::endl;
}

static void checkDomainStatus(ec_domain_t* domain) {
  ec_domain_state_t ds;
  ecrt_domain_state(domain, &ds);
  std::cout << "Domain:\tWC    " << ds.working_counter << std::endl;
  std::cout << "       \tState " << ds.wc_state << std::endl; 
}

static void parseProcessData(uint8_t* data) {
  int i;
  for (i = 0; i < 2; i++) {
    //unsigned int in = EC_READ_BIT(data + el1252.offset_in[i], 
        //el1252.offset_in[i]);
    //unsigned int status = EC_READ_BIT(data + el1252.offset_status[i], 
        //el1252.offset_status[i]);
    //unsigned int poslatch= EC_READ_BIT(data + el1252.offset_latch_pos[i], 
        //el1252.offset_latch_pos[i]);
    //unsigned int neglatch= EC_READ_BIT(data + el1252.offset_latch_neg[i], 
        //el1252.offset_latch_neg[i]);
    //printf("el1252[%i]:  in=%s\tstatus=%s\tlatchpos=%s\tlatchneg=%s\n", i,
        //in ? "true": "false", 
        //status ? "true": "false",
        //poslatch? "true": "false",
        //neglatch? "true": "false");
  }
}


_______________________________________________
etherlab-users mailing list
etherlab-users@etherlab.org
http://lists.etherlab.org/mailman/listinfo/etherlab-users

Reply via email to