00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "ros_ethercat_hardware/ethercat_device.h"
00036
00037 #include <tinyxml.h>
00038
00039 #include <iomanip>
00040
00041 bool et1x00_error_counters::isGreaterThan(unsigned value) const
00042 {
00043 if ((pdi_error > value) || (epu_error > value))
00044 {
00045 return true;
00046 }
00047
00048 for (unsigned i = 0; i < 4; ++i)
00049 {
00050 if ((port[i].rx_error > value) ||
00051 (forwarded_rx_error[i] > value) ||
00052 (lost_link[i] > value) ||
00053 (port[i].invalid_frame > value))
00054 {
00055 return true;
00056 }
00057 }
00058 return false;
00059 }
00060
00061 bool et1x00_error_counters::isGreaterThan(const et1x00_error_counters &v) const
00062 {
00063 if ((pdi_error > v.pdi_error) || (epu_error > v.epu_error))
00064 {
00065 return true;
00066 }
00067
00068 for (unsigned i = 0; i < 4; ++i)
00069 {
00070 if ((port[i].rx_error > v.port[i].rx_error) ||
00071 (forwarded_rx_error[i] > v.forwarded_rx_error[i]) ||
00072 (lost_link[i] > v.lost_link[i]) ||
00073 (port[i].invalid_frame > v.port[i].invalid_frame))
00074 {
00075 return true;
00076 }
00077 }
00078 return false;
00079 }
00080
00081 bool et1x00_dl_status::hasLink(unsigned port)
00082 {
00083 assert(port < 4);
00084 return status & (1 << (4 + port));
00085 }
00086
00087 bool et1x00_dl_status::hasCommunication(unsigned port)
00088 {
00089 assert(port < 4);
00090 return status & (1 << (9 + port * 2));
00091 }
00092
00093 bool et1x00_dl_status::isClosed(unsigned port)
00094 {
00095 assert(port < 4);
00096 return status & (1 << (8 + port * 2));
00097 }
00098
00099 void et1x00_error_counters::zero()
00100 {
00101 memset(this, 0, sizeof (et1x00_error_counters));
00102 }
00103
00104 EthercatPortDiagnostics::EthercatPortDiagnostics() :
00105 hasLink(false),
00106 isClosed(false),
00107 hasCommunication(false)
00108 {
00109 zeroTotals();
00110 }
00111
00112 void EthercatPortDiagnostics::zeroTotals()
00113 {
00114 rxErrorTotal = 0;
00115 invalidFrameTotal = 0;
00116 forwardedRxErrorTotal = 0;
00117 lostLinkTotal = 0;
00118 }
00119
00120 EthercatDeviceDiagnostics::EthercatDeviceDiagnostics() :
00121 errorCountersMayBeCleared_(false),
00122 diagnosticsFirst_(true),
00123 diagnosticsValid_(false),
00124 resetDetected_(false),
00125 devicesRespondingToNodeAddress_(-1)
00126 {
00127 zeroTotals();
00128 errorCountersPrev_.zero();
00129 }
00130
00131 void EthercatDeviceDiagnostics::zeroTotals()
00132 {
00133 pdiErrorTotal_ = 0;
00134 epuErrorTotal_ = 0;
00135 portDiagnostics_[0].zeroTotals();
00136 portDiagnostics_[1].zeroTotals();
00137 portDiagnostics_[2].zeroTotals();
00138 portDiagnostics_[3].zeroTotals();
00139 }
00140
00141 void EthercatDeviceDiagnostics::accumulate(const et1x00_error_counters &n, const et1x00_error_counters &p)
00142 {
00143 pdiErrorTotal_ += n.pdi_error - p.pdi_error;
00144 epuErrorTotal_ += n.epu_error - p.epu_error;
00145 for (unsigned i = 0; i < 4; ++i)
00146 {
00147 EthercatPortDiagnostics & pt(portDiagnostics_[i]);
00148 pt.rxErrorTotal += n.port[i].rx_error - p.port[i].rx_error;
00149 pt.forwardedRxErrorTotal += n.forwarded_rx_error[i] - p.forwarded_rx_error[i];
00150 pt.lostLinkTotal += n.lost_link[i] - p.lost_link[i];
00151 pt.invalidFrameTotal += n.port[i].invalid_frame - p.port[i].invalid_frame;
00152 }
00153 }
00154
00155 void EthercatDeviceDiagnostics::collect(EthercatCom *com, EtherCAT_SlaveHandler *sh)
00156 {
00157 diagnosticsValid_ = false;
00158 diagnosticsFirst_ = false;
00159
00160
00161
00162
00163
00164
00165
00166 {
00167
00168
00169
00170
00171 EC_Logic *logic = EC_Logic::instance();
00172 et1x00_dl_status dl_status;
00173 NPRD_Telegram nprd_telegram(logic->get_idx(),
00174 sh->get_station_address(),
00175 dl_status.BASE_ADDR,
00176 logic->get_wkc(),
00177 sizeof (dl_status),
00178 (unsigned char*) &dl_status);
00179
00180 unsigned char buf[1];
00181 uint16_t address = 0x0000;
00182 APRD_Telegram aprd_telegram(logic->get_idx(),
00183 0,
00184 address,
00185 logic->get_wkc(),
00186 sizeof (buf),
00187 buf);
00188
00189
00190
00191
00192 nprd_telegram.attach(&aprd_telegram);
00193
00194 EC_Ethernet_Frame frame(&nprd_telegram);
00195
00196
00197 if (!com->txandrx_once(&frame))
00198 {
00199
00200 goto end;
00201 }
00202
00203 devicesRespondingToNodeAddress_ = nprd_telegram.get_wkc();
00204 if (devicesRespondingToNodeAddress_ == 0)
00205 {
00206
00207 if (aprd_telegram.get_adp() >= EtherCAT_AL::instance()->get_num_slaves())
00208 {
00209 resetDetected_ = true;
00210 goto end;
00211 }
00212 }
00213 else if (devicesRespondingToNodeAddress_ > 1)
00214 {
00215
00216 goto end;
00217 }
00218 else
00219 {
00220 resetDetected_ = false;
00221 }
00222
00223
00224 for (unsigned i = 0; i < 4; ++i)
00225 {
00226 EthercatPortDiagnostics & pt(portDiagnostics_[i]);
00227 pt.hasLink = dl_status.hasLink(i);
00228 pt.isClosed = dl_status.isClosed(i);
00229 pt.hasCommunication = dl_status.hasCommunication(i);
00230 }
00231 }
00232
00233 {
00234 et1x00_error_counters e;
00235 assert(sizeof (e) == (0x314 - 0x300));
00236 if (0 != EthercatDevice::readData(com, sh, e.BASE_ADDR, &e, sizeof (e), EthercatDevice::FIXED_ADDR))
00237 {
00238 goto end;
00239 }
00240
00241
00242
00243 if (errorCountersMayBeCleared_)
00244 {
00245 if (!e.isGreaterThan(errorCountersPrev_))
00246 {
00247 errorCountersPrev_.zero();
00248 }
00249 errorCountersMayBeCleared_ = false;
00250 }
00251 if (errorCountersPrev_.isGreaterThan(e))
00252 {
00253 ROS_ERROR("Device %d : previous port error counters less current values", sh->get_ring_position());
00254 }
00255
00256
00257 this->accumulate(e, errorCountersPrev_);
00258 errorCountersPrev_ = e;
00259
00260
00261 if (e.isGreaterThan(50))
00262 {
00263 if (0 != EthercatDevice::readWriteData(com, sh, e.BASE_ADDR, &e, sizeof (e), EthercatDevice::FIXED_ADDR))
00264 {
00265
00266 errorCountersMayBeCleared_ = true;
00267 goto end;
00268 }
00269
00270 this->accumulate(e, errorCountersPrev_);
00271 errorCountersPrev_.zero();
00272 }
00273 }
00274
00275
00276 diagnosticsValid_ = true;
00277
00278 end:
00279 return;
00280 }
00281
00282 void EthercatDeviceDiagnostics::publish(diagnostic_updater::DiagnosticStatusWrapper &d, unsigned numPorts) const
00283 {
00284 if (numPorts > 4)
00285 {
00286 assert(numPorts < 4);
00287 numPorts = 4;
00288 }
00289 assert(numPorts > 0);
00290
00291 d.addf("Reset detected", "%s", (resetDetected_ ? "Yes" : "No"));
00292 d.addf("Valid", "%s", (diagnosticsValid_ ? "Yes" : "No"));
00293
00294 d.addf("EPU Errors", "%lld", epuErrorTotal_);
00295 d.addf("PDI Errors", "%lld", pdiErrorTotal_);
00296 ostringstream os, port;
00297 for (unsigned i = 0; i < numPorts; ++i)
00298 {
00299 const EthercatPortDiagnostics & pt(portDiagnostics_[i]);
00300 port.str("");
00301 port << " Port " << i;
00302 os.str("");
00303 os << "Status" << port.str();
00304 d.addf(os.str(), "%s Link, %s, %s Comm",
00305 pt.hasLink ? "Has" : "No",
00306 pt.isClosed ? "Closed" : "Open",
00307 pt.hasCommunication ? "Has" : "No");
00308 os.str("");
00309 os << "RX Error" << port.str();
00310 d.addf(os.str(), "%lld", pt.rxErrorTotal);
00311 os.str("");
00312 os << "Forwarded RX Error" << port.str();
00313 d.addf(os.str(), "%lld", pt.forwardedRxErrorTotal);
00314 os.str("");
00315 os << "Invalid Frame" << port.str();
00316 d.addf(os.str(), "%lld", pt.invalidFrameTotal);
00317 os.str("");
00318 os << "Lost Link" << port.str();
00319 d.addf(os.str(), "%lld", pt.lostLinkTotal);
00320 }
00321
00322 if (resetDetected_)
00323 {
00324 d.mergeSummaryf(d.ERROR, "Device reset likely");
00325 }
00326 else if (devicesRespondingToNodeAddress_ > 1)
00327 {
00328 d.mergeSummaryf(d.ERROR, "More than one device (%d) responded to node address", devicesRespondingToNodeAddress_);
00329 }
00330 else
00331 {
00332 if (diagnosticsFirst_)
00333 {
00334 d.mergeSummaryf(d.WARN, "Have not yet collected diagnostics");
00335 }
00336 else if (!diagnosticsValid_)
00337 {
00338 d.mergeSummaryf(d.WARN, "Could not collect diagnostics");
00339 }
00340 else
00341 {
00342 if (!portDiagnostics_[0].hasLink)
00343 {
00344 d.mergeSummaryf(d.WARN, "No link on port 0");
00345 }
00346 }
00347 }
00348 }
00349
00350 void EthercatDevice::construct(EtherCAT_SlaveHandler *sh, int &start_address)
00351 {
00352 sh_ = sh;
00353 sh->set_fmmu_config(new EtherCAT_FMMU_Config(0));
00354 sh->set_pd_config(new EtherCAT_PD_Config(0));
00355 }
00356
00357 EthercatDevice::EthercatDevice() : use_ros_(true)
00358 {
00359 sh_ = NULL;
00360 command_size_ = 0;
00361 status_size_ = 0;
00362 newDiagnosticsIndex_ = 0;
00363
00364 int error = pthread_mutex_init(&newDiagnosticsIndexLock_, NULL);
00365 if (error != 0)
00366 {
00367 ROS_FATAL("Initializing indexLock failed : %s", strerror(error));
00368 sleep(1);
00369 exit(EXIT_FAILURE);
00370 }
00371
00372 error = pthread_mutex_init(&diagnosticsLock_, NULL);
00373 if (error != 0)
00374 {
00375 ROS_FATAL("Initializing diagnositcsLock failed : %s", strerror(error));
00376 sleep(1);
00377 exit(EXIT_FAILURE);
00378 }
00379 }
00380
00381 void EthercatDevice::collectDiagnostics(EthercatCom *com)
00382 {
00383
00384 pthread_mutex_lock(&diagnosticsLock_);
00385
00386
00387 unsigned oldDiagnosticsIndex = (newDiagnosticsIndex_ + 1)&1;
00388 const EthercatDeviceDiagnostics &newDiag = deviceDiagnostics[newDiagnosticsIndex_];
00389 EthercatDeviceDiagnostics &oldDiag = deviceDiagnostics[oldDiagnosticsIndex];
00390
00391
00392 oldDiag = newDiag;
00393
00394
00395
00396 oldDiag.collect(com, sh_);
00397
00398
00399
00400
00401 pthread_mutex_lock(&newDiagnosticsIndexLock_);
00402 newDiagnosticsIndex_ = oldDiagnosticsIndex;
00403 pthread_mutex_unlock(&newDiagnosticsIndexLock_);
00404
00405
00406 pthread_mutex_unlock(&diagnosticsLock_);
00407 }
00408
00409 int EthercatDevice::readWriteData(EthercatCom *com, EtherCAT_SlaveHandler *sh, uint16_t address, void* buffer, uint16_t length, AddrMode addrMode)
00410 {
00411 unsigned char *p = (unsigned char *) buffer;
00412 EC_Logic *logic = EC_Logic::instance();
00413
00414 NPRW_Telegram nprw_telegram(logic->get_idx(),
00415 sh->get_station_address(),
00416 address,
00417 logic->get_wkc(),
00418 length,
00419 p);
00420
00421 APRW_Telegram aprw_telegram(logic->get_idx(),
00422 -sh->get_ring_position(),
00423 address,
00424 logic->get_wkc(),
00425 length,
00426 p);
00427
00428
00429 EC_Telegram * telegram = NULL;
00430 if (addrMode == FIXED_ADDR)
00431 {
00432 telegram = &nprw_telegram;
00433 }
00434 else if (addrMode == POSITIONAL_ADDR)
00435 {
00436 telegram = &aprw_telegram;
00437 }
00438 else
00439 {
00440 assert(0);
00441 return -1;
00442 }
00443
00444
00445 EC_Ethernet_Frame frame(telegram);
00446
00447
00448 if (!com->txandrx_once(&frame))
00449 {
00450 return -1;
00451 }
00452
00453
00454 if (telegram->get_wkc() != 3)
00455 {
00456 return -2;
00457 }
00458
00459 return 0;
00460 }
00461
00462 int EthercatDevice::readData(EthercatCom *com, EtherCAT_SlaveHandler *sh, uint16_t address, void* buffer, uint16_t length, AddrMode addrMode)
00463 {
00464 unsigned char *p = (unsigned char *) buffer;
00465 EC_Logic *logic = EC_Logic::instance();
00466
00467 NPRD_Telegram nprd_telegram(logic->get_idx(),
00468 sh->get_station_address(),
00469 address,
00470 logic->get_wkc(),
00471 length,
00472 p);
00473
00474 APRD_Telegram aprd_telegram(logic->get_idx(),
00475 -sh->get_ring_position(),
00476 address,
00477 logic->get_wkc(),
00478 length,
00479 p);
00480
00481
00482 EC_Telegram * telegram = NULL;
00483 if (addrMode == FIXED_ADDR)
00484 {
00485 telegram = &nprd_telegram;
00486 }
00487 else if (addrMode == POSITIONAL_ADDR)
00488 {
00489 telegram = &aprd_telegram;
00490 }
00491 else
00492 {
00493 assert(0);
00494 return -1;
00495 }
00496
00497
00498 EC_Ethernet_Frame frame(telegram);
00499
00500
00501 if (!com->txandrx(&frame))
00502 {
00503 return -1;
00504 }
00505
00506
00507 if (telegram->get_wkc() != 1)
00508 {
00509 return -2;
00510 }
00511
00512 return 0;
00513 }
00514
00515 int EthercatDevice::writeData(EthercatCom *com, EtherCAT_SlaveHandler *sh, uint16_t address, void const* buffer, uint16_t length, AddrMode addrMode)
00516 {
00517 unsigned char const *p = (unsigned char const*) buffer;
00518 EC_Logic *logic = EC_Logic::instance();
00519
00520 NPWR_Telegram npwr_telegram(logic->get_idx(),
00521 sh->get_station_address(),
00522 address,
00523 logic->get_wkc(),
00524 length,
00525 p);
00526
00527 APWR_Telegram apwr_telegram(logic->get_idx(),
00528 -sh->get_ring_position(),
00529 address,
00530 logic->get_wkc(),
00531 length,
00532 p);
00533
00534
00535 EC_Telegram * telegram = NULL;
00536 if (addrMode == FIXED_ADDR)
00537 {
00538 telegram = &npwr_telegram;
00539 }
00540 else if (addrMode == POSITIONAL_ADDR)
00541 {
00542 telegram = &apwr_telegram;
00543 }
00544 else
00545 {
00546 assert(0);
00547 return -1;
00548 }
00549
00550
00551 EC_Ethernet_Frame frame(telegram);
00552
00553
00554 if (!com->txandrx(&frame))
00555 {
00556 return -1;
00557 }
00558
00559 if (telegram->get_wkc() != 1)
00560 {
00561 return -2;
00562 }
00563
00564 return 0;
00565 }
00566
00567 void EthercatDevice::ethercatDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &d, unsigned numPorts)
00568 {
00569 if (numPorts > 4)
00570 {
00571 assert(numPorts < 4);
00572 numPorts = 4;
00573 }
00574
00575
00576
00577
00578 pthread_mutex_lock(&newDiagnosticsIndexLock_);
00579
00580 const EthercatDeviceDiagnostics &newDiag = deviceDiagnostics[newDiagnosticsIndex_];
00581 newDiag.publish(d, numPorts);
00582
00583 pthread_mutex_unlock(&newDiagnosticsIndexLock_);
00584 }
00585
00586 void EthercatDevice::diagnostics(diagnostic_updater::DiagnosticStatusWrapper &d, unsigned char *buffer)
00587 {
00588 stringstream str;
00589 str << "EtherCAT Device (" << std::setw(2) << std::setfill('0') << sh_->get_ring_position() << ")";
00590 d.name = str.str();
00591 str.str("");
00592 str << sh_->get_product_code() << '-' << sh_->get_serial();
00593 d.hardware_id = str.str();
00594
00595 d.message = "";
00596 d.level = 0;
00597
00598 d.clear();
00599 d.addf("Position", "%02d", sh_->get_ring_position());
00600 d.addf("Product code", "%08x", sh_->get_product_code());
00601 d.addf("Serial", "%08x", sh_->get_serial());
00602 d.addf("Revision", "%08x", sh_->get_revision());
00603
00604 this->ethercatDiagnostics(d, 4);
00605 }
00606
00607 void EthercatDevice::multiDiagnostics(vector<diagnostic_msgs::DiagnosticStatus> &vec, unsigned char *buffer)
00608 {
00609
00610 diagnostic_status_.clearSummary();
00611 diagnostic_status_.clear();
00612
00613
00614 diagnostics(diagnostic_status_, buffer);
00615 vec.push_back(diagnostic_status_);
00616 }