00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00023
00024
00025 #include "CanOpenController.h"
00026 #include <icl_hardware_can/tCanDeviceDummy.h>
00027 #include "Logging.h"
00028 #include "ds301.h"
00029 #include "sync.h"
00030 #include "exceptions.h"
00031
00032 #include <cstdlib>
00033 #include <boost/filesystem.hpp>
00034
00035 namespace icl_hardware {
00036 namespace canopen_schunk {
00037
00038 CanOpenController::CanOpenController(const std::string can_device_identifier,
00039 const uint32_t baud_rate,
00040 const std::string& resource_folder_location
00041 )
00042 : m_can_device_name(can_device_identifier),
00043 m_can_device_flags(O_RDWR|O_NONBLOCK),
00044 m_can_device_acceptance_code(0xff),
00045 m_can_device_acceptance_mask(0xff),
00046 m_can_device_send_fifo_size(300),
00047 m_can_device_receive_fifo_size(2000),
00048 m_can_device_baud_rate(baud_rate),
00049 m_heartbeat_monitor(new HeartBeatMonitor()),
00050 m_polling_period_ms(1),
00051 m_resource_folder_location(resource_folder_location),
00052 m_ws_broadcast_counter(0),
00053 m_ws_broadcast_rate(5)
00054 {
00055 init();
00056 }
00057
00058 CanOpenController::~CanOpenController ()
00059 {
00060
00061 if (m_receive_thread)
00062 {
00063 m_receive_thread->stop();
00064 }
00065 }
00066
00067 void CanOpenController::initNodes (const int16_t node_id)
00068 {
00069 for (std::map<uint8_t, DS301Node::Ptr>::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
00070 {
00071 if (it->first == node_id || node_id < 0)
00072 {
00073 it->second->initNode();
00074 }
00075 }
00076 }
00077
00078 void CanOpenController::processCanMsgCallback ( const can::tCanMessage& msg )
00079 {
00080 if (msg.id == ds301::ID_NMT)
00081 {
00082 LOGGING_DEBUG_C (CanOpen, CanOpenController, "NMT MESSAGE RECEIVED" << endl);
00083 LOGGING_TRACE_C (CanOpen, CanOpenController,
00084 "Message id: " << msg.id << endl
00085 << "Message length: " << msg.dlc << endl
00086 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00087 }
00088 else if (msg.id == ds301::ID_SYNC)
00089 {
00090 LOGGING_DEBUG_C (CanOpen, CanOpenController, "SYNC MESSAGE RECEIVED" << endl);
00091 LOGGING_TRACE_C (CanOpen, CanOpenController,
00092 "Message id: " << msg.id << endl
00093 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00094 }
00095 else if (msg.id >= ds301::ID_EMCY_MIN && msg.id <= ds301::ID_EMCY_MAX)
00096 {
00097 LOGGING_DEBUG_C (CanOpen, CanOpenController, "EMCY MESSAGE RECEIVED" << endl);
00098 LOGGING_TRACE_C (CanOpen, CanOpenController,
00099 "Message id: " << msg.id << endl
00100 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00101 DS301Node::Ptr node = getNodeById(msg.id - ds301::ID_EMCY_MIN+1);
00102 if (node)
00103 {
00104 try
00105 {
00106 node->m_emcy->update(msg);
00107 }
00108 catch (const std::exception& e)
00109 {
00110 LOGGING_ERROR (CanOpen, "Exception thrown in EMCY update function: " << e.what() << endl);
00111 }
00112 }
00113 }
00114 else if (msg.id == ds301::ID_TIME)
00115 {
00116 LOGGING_DEBUG_C (CanOpen, CanOpenController, "TIME MESSAGE RECEIVED" << endl);
00117 LOGGING_TRACE_C (CanOpen, CanOpenController,
00118 "Message id: " << msg.id << endl
00119 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00120 }
00121 else if (msg.id >= ds301::ID_TPDO1_MIN && msg.id <= ds301::ID_TPDO1_MAX)
00122 {
00123 LOGGING_DEBUG_C (CanOpen, CanOpenController, "TPDO1 MESSAGE for node " << msg.id - ds301::ID_TPDO1_MIN+1 << " RECEIVED" << endl);
00124 LOGGING_TRACE_C (CanOpen, CanOpenController,
00125 "Message id: " << msg.id << endl
00126 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00127 DS301Node::Ptr node = getNodeById(msg.id - ds301::ID_TPDO1_MIN+1);
00128 if (node)
00129 {
00130 try
00131 {
00132 node->m_tpdos.at(0)->update(msg);
00133 }
00134 catch (const std::exception& e)
00135 {
00136 LOGGING_ERROR (CanOpen, "Exception thrown in PDO update function: " << e.what() << endl);
00137 }
00138 }
00139 }
00140 else if (msg.id >= ds301::ID_RPDO1_MIN && msg.id <= ds301::ID_RPDO1_MAX)
00141 {
00142 LOGGING_DEBUG_C (CanOpen, CanOpenController, "RPDO1 MESSAGE RECEIVED" << endl);
00143 LOGGING_TRACE_C (CanOpen, CanOpenController,
00144 "Message id: " << msg.id << endl
00145 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00146 }
00147 else if (msg.id >= ds301::ID_TPDO2_MIN && msg.id <= ds301::ID_TPDO2_MAX)
00148 {
00149 LOGGING_DEBUG_C (CanOpen, CanOpenController, "TPDO2 MESSAGE RECEIVED" << endl);
00150 LOGGING_TRACE_C (CanOpen, CanOpenController,
00151 "Message id: " << msg.id << endl
00152 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00153 DS301Node::Ptr node = getNodeById(msg.id - ds301::ID_TPDO2_MIN+1);
00154 if (node)
00155 {
00156 try
00157 {
00158 node->m_tpdos.at(1)->update(msg);
00159 }
00160 catch (const std::exception& e)
00161 {
00162 LOGGING_ERROR (CanOpen, "Exception thrown in PDO update function: " << e.what() << endl);
00163 }
00164 }
00165 }
00166 else if (msg.id >= ds301::ID_RPDO2_MIN && msg.id <= ds301::ID_RPDO2_MAX)
00167 {
00168 LOGGING_DEBUG_C (CanOpen, CanOpenController, "RPDO2 MESSAGE RECEIVED" << endl);
00169 LOGGING_TRACE_C (CanOpen, CanOpenController,
00170 "Message id: " << msg.id << endl
00171 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00172 }
00173 else if (msg.id >= ds301::ID_TPDO3_MIN && msg.id <= ds301::ID_TPDO3_MAX)
00174 {
00175 LOGGING_DEBUG_C (CanOpen, CanOpenController, "TPDO3 MESSAGE RECEIVED" << endl);
00176 LOGGING_TRACE_C (CanOpen, CanOpenController,
00177 "Message id: " << msg.id << endl
00178 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00179 DS301Node::Ptr node = getNodeById(msg.id - ds301::ID_TPDO3_MIN+1);
00180 if (node)
00181 {
00182 try
00183 {
00184 node->m_tpdos.at(2)->update(msg);
00185 }
00186 catch (const std::exception& e)
00187 {
00188 LOGGING_ERROR (CanOpen, "Exception thrown in PDO update function: " << e.what() << endl);
00189 }
00190 }
00191 }
00192 else if (msg.id >= ds301::ID_RPDO3_MIN && msg.id <= ds301::ID_RPDO3_MAX)
00193 {
00194 LOGGING_DEBUG_C (CanOpen, CanOpenController, "RPDO3 MESSAGE RECEIVED" << endl);
00195 LOGGING_TRACE_C (CanOpen, CanOpenController,
00196 "Message id: " << msg.id << endl
00197 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00198 }
00199 else if (msg.id >= ds301::ID_TPDO4_MIN && msg.id <= ds301::ID_TPDO4_MAX)
00200 {
00201 LOGGING_DEBUG_C (CanOpen, CanOpenController, "TPDO4 MESSAGE RECEIVED" << endl);
00202 LOGGING_TRACE_C (CanOpen, CanOpenController,
00203 "Message id: " << msg.id << endl
00204 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00205 DS301Node::Ptr node = getNodeById(msg.id - ds301::ID_TPDO4_MIN+1);
00206 if (node)
00207 {
00208 try
00209 {
00210 node->m_tpdos.at(3)->update(msg);
00211 }
00212 catch (const std::exception& e)
00213 {
00214 LOGGING_ERROR (CanOpen, "Exception thrown in PDO update function: " << e.what() << endl);
00215 }
00216 }
00217 }
00218 else if (msg.id >= ds301::ID_RPDO4_MIN && msg.id <= ds301::ID_RPDO4_MAX)
00219 {
00220 LOGGING_DEBUG_C (CanOpen, CanOpenController, "RPDO4 MESSAGE RECEIVED" << endl);
00221 LOGGING_TRACE_C (CanOpen, CanOpenController,
00222 "Message id: " << msg.id << endl
00223 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00224 }
00225 else if (msg.id >= ds301::ID_TSDO_MIN && msg.id <= ds301::ID_TSDO_MAX)
00226 {
00227 LOGGING_DEBUG_C (CanOpen, CanOpenController, "TSDO MESSAGE RECEIVED" << endl);
00228 LOGGING_TRACE_C (CanOpen, CanOpenController,
00229 "Message id: " << msg.id << endl
00230 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00231 DS301Node::Ptr node = getNodeById(msg.id - ds301::ID_TSDO_MIN+1);
00232 if (node)
00233 {
00234 try
00235 {
00236 node->m_sdo.update(msg);
00237 }
00238 catch (const ResponseException& e)
00239 {
00240 LOGGING_ERROR (CanOpen, "Exception thrown in SDO update function: " << e.what() << endl);
00241 }
00242 }
00243 }
00244 else if (msg.id >= ds301::ID_RSDO_MIN && msg.id <= ds301::ID_RSDO_MAX)
00245 {
00246 LOGGING_DEBUG_C (CanOpen, CanOpenController, "RSDO MESSAGE RECEIVED" << endl);
00247 LOGGING_TRACE_C (CanOpen, CanOpenController,
00248 "Message id: " << msg.id << endl
00249 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00250 DS301Node::Ptr node = getNodeById(msg.id - ds301::ID_RSDO_MIN+1);
00251 if (node)
00252 {
00253 try
00254 {
00255 node->m_sdo.update(msg);
00256 }
00257 catch (const ResponseException& e)
00258 {
00259 LOGGING_ERROR (CanOpen, "Exception thrown in SDO update function: " << e.what() << endl);
00260 }
00261 }
00262 }
00263 else if (msg.id >= ds301::ID_NMT_ERROR_MIN && msg.id <= ds301::ID_NMT_ERROR_MAX)
00264 {
00265 LOGGING_DEBUG_C (CanOpen, CanOpenController, "NMT_ERROR MESSAGE RECEIVED" << endl);
00266 LOGGING_TRACE_C (CanOpen, CanOpenController,
00267 "Message id: " << msg.id << endl
00268 << "Data: " << hexArrayToString(msg.data, msg.dlc) << endl);
00269 uint8_t node_id = msg.id - ds301::ID_NMT_ERROR_MIN+1;
00270 DS301Node::Ptr node = getNodeById(node_id);
00271
00272 if (node)
00273 {
00274 try
00275 {
00276 node->m_nmt.update(msg);
00277 }
00278 catch (const ResponseException& e)
00279 {
00280 LOGGING_ERROR (CanOpen, "Exception thrown in NMT update function: " << e.what() << endl);
00281 }
00282 if (msg.data[0] != 0x0)
00283 {
00284 m_heartbeat_monitor->addHeartbeat(node_id);
00285 }
00286 }
00287 else if ( msg.dlc == 1 && msg.data[0] == 0x0)
00288 {
00289
00290 LOGGING_INFO_C (CanOpen, CanOpenController, "NMT bootup of node " << msg.id - ds301::ID_NMT_ERROR_MIN+1 << endl);
00291 }
00292 }
00293 }
00294
00295 void CanOpenController::reconnectCanDevice(const std::string& can_identifier, const uint32_t baud_rate)
00296 {
00297 if (baud_rate != 0)
00298 {
00299 m_can_device_baud_rate = baud_rate;
00300 }
00301 m_can_device_name = can_identifier;
00302
00303 if (m_receive_thread)
00304 {
00305 m_receive_thread->stop();
00306 }
00307
00308 try
00309 {
00310 init();
00311 }
00312 catch (const DeviceException& e)
00313 {
00314 LOGGING_ERROR_C (CanOpen, CanOpenController, "Initializing device failed. Reason: " << e.what());
00315 }
00316 }
00317
00318 void CanOpenController::init()
00319 {
00320 #ifdef _IC_BUILDER_ICL_COMM_WEBSOCKET_
00321 m_ws_broadcaster = boost::shared_ptr<icl_comm::websocket::WsBroadcaster>(new icl_comm::websocket::WsBroadcaster(icl_comm::websocket::WsBroadcaster::eRT_LWA4P));
00322 #endif // _IC_BUILDER_ICL_COMM_WEBSOCKET_
00323
00324
00325 getResources();
00326
00327 if (m_can_device_name == "Dummy")
00328 {
00329 m_can_device.reset(new icl_hardware::can::tCanDeviceDummy( m_can_device_name.c_str(),
00330 m_can_device_flags,
00331 m_can_device_acceptance_code,
00332 m_can_device_acceptance_mask,
00333 m_can_device_baud_rate,
00334 m_can_device_send_fifo_size,
00335 m_can_device_receive_fifo_size
00336 ));
00337 }
00338 else if (m_can_device_name == "auto")
00339 {
00340 const boost::array<const std::string, 4> names = {"/dev/pcanusb0","/dev/pcanusb1","/dev/pcanusb2","/dev/pcanusb3"};
00341 bool can_found = false;
00342 LOGGING_INFO (CanOpen, "CAN Device was set to auto. " << endl);
00343
00344 for (size_t num = 0; num < names.size() ; ++num)
00345 {
00346 m_can_device_name = names[num];
00347 LOGGING_INFO(CanOpen, "Trying CAN device: " << m_can_device_name << "... " << endl);
00348 try
00349 {
00350 m_can_device.reset(icl_hardware::can::tCanDevice::Create( m_can_device_name.c_str(),
00351 m_can_device_flags,
00352 m_can_device_acceptance_code,
00353 m_can_device_acceptance_mask,
00354 m_can_device_baud_rate,
00355 m_can_device_send_fifo_size,
00356 m_can_device_receive_fifo_size
00357 ));
00358
00359 if (m_can_device)
00360 {
00361 if (!m_can_device->IsInitialized())
00362 {
00363 std::stringstream ss;
00364 continue;
00365 }
00366 }
00367 can_found = true;
00368
00369 break;
00370
00371 }
00372 catch (DeviceException const& e)
00373 {
00374 LOGGING_INFO(CanOpen, e.what() << endl);
00375 can_found = false;
00376 }
00377 }
00378 if (!can_found)
00379 {
00380 LOGGING_ERROR(CanOpen, " CAN DEVICE COULD NOT BE OPENED. \n >> Giving up.");
00381 exit(-123);
00382 return;
00383 }
00384 }
00385 else
00386 {
00387 m_can_device.reset(icl_hardware::can::tCanDevice::Create( m_can_device_name.c_str(),
00388 m_can_device_flags,
00389 m_can_device_acceptance_code,
00390 m_can_device_acceptance_mask,
00391 m_can_device_baud_rate,
00392 m_can_device_send_fifo_size,
00393 m_can_device_receive_fifo_size
00394 ));
00395 }
00396
00397 if (m_can_device)
00398 {
00399 if (!m_can_device->IsInitialized())
00400 {
00401 std::stringstream ss;
00402 ss << "FATAL: COULD NOT INITIALIZE CAN DEVICE in " << m_can_device_name;
00403
00404 throw DeviceException(ss.str());
00405 }
00406 }
00407 else
00408 {
00409 std::stringstream ss;
00410 ss << "FATAL: COULD NOT GET VALID CAN DEVICE in " << m_can_device_name;
00411
00412 throw DeviceException(ss.str());
00413 }
00414
00415 m_receive_thread.reset(new CanOpenReceiveThread(icl_core::TimeSpan::createFromMSec(m_polling_period_ms),
00416 m_can_device,
00417 boost::bind(&CanOpenController::processCanMsgCallback, this, _1)
00418 ));
00419
00420 if (!m_receive_thread)
00421 {
00422 throw DeviceException("FATAL: Could not start listener thread for CAN bus.");
00423 }
00424
00425
00426 addGroup<DS402Group>("default");
00427 m_heartbeat_monitor->registerErrorCallback(boost::bind(&CanOpenController::stopAll, this));
00428 }
00429
00430 void CanOpenController::deleteGroup(const std::string& identifier)
00431 {
00432 std::string sanitized_identifier = sanitizeString(identifier);
00433
00434 std::map<std::string, DS301Group::Ptr>::iterator group_it;
00435 group_it = m_groups.find(sanitized_identifier);
00436 if (group_it != m_groups.end())
00437 {
00438 std::vector<uint8_t> deleted_node_ids;
00439 group_it->second->deleteNodes(deleted_node_ids);
00440
00441
00442 for (std::vector<uint8_t>::iterator it = deleted_node_ids.begin();
00443 it != deleted_node_ids.end();
00444 ++it)
00445 {
00446
00447 std::map<uint8_t, DS301Node::Ptr>::iterator node_it = m_nodes.find(*it);
00448 assert(node_it->second.use_count() == 1);
00449 m_nodes.erase(node_it);
00450 }
00451
00452 m_groups.erase(group_it);
00453 }
00454 else
00455 {
00456 LOGGING_ERROR_C(CanOpen, CanOpenController, "No group with the given identifer " << sanitized_identifier
00457 << " exists. Not deleting anything." << endl);
00458 }
00459 }
00460
00461 void CanOpenController::deleteNode(const uint8_t node_id)
00462 {
00463
00464 for (std::map<std::string, DS301Group::Ptr>::iterator it = m_groups.begin();
00465 it != m_groups.end();
00466 ++it)
00467 {
00468 if (it->second->deleteNodeFromId(node_id))
00469 {
00470
00471 break;
00472 }
00473 }
00474
00475
00476 std::map<uint8_t, DS301Node::Ptr>::iterator node_it = m_nodes.find(node_id);
00477 assert(node_it->second.use_count() == 1);
00478 m_nodes.erase(node_it);
00479 }
00480
00481 DS301Node::Ptr CanOpenController::getNodeById(const uint8_t node_id)
00482 {
00483 std::map<uint8_t, DS301Node::Ptr>::iterator node_it = m_nodes.find(node_id);
00484 if (node_it == m_nodes.end())
00485 {
00486 LOGGING_ERROR_C(CanOpen, CanOpenController, "A node with the given ID " << node_id <<
00487 " does not exist. Therefore this CAN message will be ignored." << endl);
00488
00489 return DS301Node::Ptr();
00490 }
00491 return node_it->second;
00492 }
00493
00494 void CanOpenController::getResources()
00495 {
00496 boost::filesystem::path resources_path(m_resource_folder_location);
00497
00498 if (m_resource_folder_location == "")
00499 {
00500 char const* tmp = std::getenv("CANOPEN_RESOURCE_PATH");
00501 if (tmp == NULL)
00502 {
00503 LOGGING_WARNING_C(
00504 CanOpen,
00505 CanOpenController,
00506 "The environment variable 'CANOPEN_RESOURCE_PATH' could not be read. Using relative path 'resources/'" << endl);
00507 resources_path = boost::filesystem::path("resources");
00508 }
00509 else
00510 {
00511 resources_path = boost::filesystem::path(tmp);
00512 }
00513 }
00514
00515 std::string sdo_errors_filename = (resources_path / boost::filesystem::path("SDO.ini")).string();
00516 SDO::addErrorMapFromFile( sdo_errors_filename );
00517
00518 std::string emcy_emergency_errors_filename = (resources_path / boost::filesystem::path("EMCY.ini")).string();
00519 EMCY::addEmergencyErrorMap( emcy_emergency_errors_filename, "emergency_errors");
00520 EMCY::addErrorRegisterMap( emcy_emergency_errors_filename, "error_registers");
00521
00522 emcy_emergency_errors_filename = (resources_path / boost::filesystem::path("EMCY_DS402.ini")).string();
00523 EMCY::addEmergencyErrorMap( emcy_emergency_errors_filename, "emergency_errors");
00524 }
00525
00526 void CanOpenController::syncAll()
00527 {
00528 for (std::map<uint8_t, DS301Node::Ptr>::iterator it = m_nodes.begin();
00529 it != m_nodes.end();
00530 ++it)
00531 {
00532 it->second->downloadPDOs();
00533 }
00534
00535 sendSync (m_can_device);
00536
00537 for (std::map<uint8_t, DS301Node::Ptr>::iterator it = m_nodes.begin();
00538 it != m_nodes.end();
00539 ++it)
00540 {
00541 it->second->uploadPDOs();
00542 }
00543
00544 #ifdef _IC_BUILDER_ICL_COMM_WEBSOCKET_
00545 if(m_ws_broadcast_counter % m_ws_broadcast_rate == 0)
00546 {
00547 if (!m_ws_broadcaster->sendState())
00548 {
00549
00550
00551
00552 }
00553 m_ws_broadcast_counter = 0;
00554 }
00555 ++m_ws_broadcast_counter;
00556 #endif // _IC_BUILDER_ICL_COMM_WEBSOCKET_
00557
00558 }
00559
00560 void CanOpenController::stopAll()
00561 {
00562 LOGGING_INFO (CanOpen, "Stop of all nodes requested!" << endl);
00563 for (std::map<uint8_t, DS301Node::Ptr>::iterator it = m_nodes.begin();
00564 it != m_nodes.end();
00565 ++it)
00566 {
00567 it->second->stopNode();
00568 }
00569 }
00570
00571 std::vector< uint8_t > CanOpenController::getNodeList()
00572 {
00573 std::vector <uint8_t> node_list;
00574
00575 size_t i=0;
00576 for (std::map<uint8_t, DS301Node::Ptr>::iterator it = m_nodes.begin();
00577 it != m_nodes.end();
00578 ++it)
00579 {
00580 it->second->downloadPDOs();
00581 node_list.push_back(it->second->getNodeId());
00582 ++i;
00583 }
00584
00585 return node_list;
00586 }
00587
00588
00589
00590 void CanOpenController::enablePPMotion(const int16_t node_id)
00591 {
00592 syncAll();
00593 usleep(5000);
00594
00595 LOGGING_TRACE_C (CanOpen, CanOpenController, "in function " << __FUNCTION__ << endl);
00596
00597 for (std::map<std::string, DS301Group::Ptr>::iterator it = m_groups.begin();
00598 it != m_groups.end();
00599 ++it)
00600 {
00601 DS402Group::Ptr group_ds402 = boost::dynamic_pointer_cast<DS402Group>(it->second);
00602 if (group_ds402)
00603 {
00604 group_ds402->startPPMovement(node_id);
00605 }
00606 }
00607
00608 syncAll();
00609 usleep(5000);
00610
00611 for (std::map<std::string, DS301Group::Ptr>::iterator it = m_groups.begin();
00612 it != m_groups.end();
00613 ++it)
00614 {
00615 DS402Group::Ptr group_ds402 = boost::dynamic_pointer_cast<DS402Group>(it->second);
00616 if (group_ds402)
00617 {
00618 group_ds402->acceptPPTargets(node_id);
00619 }
00620 }
00621 syncAll();
00622 usleep(5000);
00623
00624 }
00625
00626 }}