15 #ifndef CANOPEN_BASE_DRIVER__LELY_BRIDGE_HPP_
16 #define CANOPEN_BASE_DRIVER__LELY_BRIDGE_HPP_
20 #include <lely/co/dcf.hpp>
21 #include <lely/co/dev.hpp>
22 #include <lely/co/obj.hpp>
23 #include <lely/coapp/fiber_driver.hpp>
24 #include <lely/coapp/master.hpp>
25 #include <lely/coapp/sdo_error.hpp>
26 #include <lely/ev/co_task.hpp>
27 #include <lely/ev/future.hpp>
30 #include <condition_variable>
34 #include <rclcpp/rclcpp.hpp>
36 #include <system_error>
40 #include <boost/lockfree/queue.hpp>
41 #include <boost/optional.hpp>
42 #include <boost/thread.hpp>
46 using namespace std::chrono_literals;
57 typedef std::map<uint16_t, std::map<uint8_t, pdo_mapping>>
PDOMap;
69 std::shared_ptr<PDOMap> pdo_map = std::make_shared<PDOMap>();
113 for (
int index = 0; index < 256; index++)
115 for (
int subindex = 1; subindex < 9; subindex++)
117 auto obj = find(0x1600 + index, subindex);
124 data = obj->getVal<CO_DEFTYPE_UNSIGNED32>();
126 uint8_t tmps = (data >> 8) & 0xFF;
127 uint16_t tmpi = (data >> 16) & 0xFFFF;
135 (*map)[tmpi][tmps] = mapping;
136 std::cout <<
"Found rpdo mapped object: index=" << std::hex << (int)tmpi
137 <<
" subindex=" << (
int)tmps << std::endl;
143 for (
int index = 0; index < 256; index++)
145 for (
int subindex = 1; subindex < 9; subindex++)
147 auto obj = find(0x1A00 + index, subindex);
154 data = obj->getVal<CO_DEFTYPE_UNSIGNED32>();
156 uint8_t tmps = (data >> 8) & 0xFF;
157 uint16_t tmpi = (data >> 16) & 0xFFFF;
166 (*map)[tmpi][tmps] = mapping;
167 std::cout <<
"Found tpdo mapped object: index=" << std::hex << (int)tmpi
168 <<
" subindex=" << (
int)tmps << std::endl;
177 for (
int i = 0; i < 256; i++)
179 if (this->checkObjInPDO(i, 0x1600, idx, subidx))
191 for (
int i = 0; i < 256; i++)
193 if (this->checkObjInPDO(i, 0x1A00, idx, subidx))
201 bool checkObjInPDO(uint8_t pdo, uint16_t mapping_idx, uint16_t idx, uint8_t subindex)
203 for (
int i = 1; i < 9; i++)
205 auto obj = find(mapping_idx + pdo, i);
212 data = obj->getVal<CO_DEFTYPE_UNSIGNED32>();
214 uint8_t tmps = (data >> 8) & 0xFF;
215 uint16_t tmpi = (data >> 16) & 0xFFFF;
217 if (tmps == subindex && tmpi == idx)
219 std::cout <<
"Found object in pdo: " << (int)pdo << std::endl;
249 const char *
name() const noexcept override;
250 std::
string message(
int ev) const override;
330 void OnSync(uint8_t cnt,
const time_point & t) noexcept
override
332 if (on_sync_function_ !=
nullptr)
352 void OnState(canopen::NmtState state) noexcept
override;
364 virtual void OnBoot(canopen::NmtState st,
char es, const ::std::string & what) noexcept
override;
386 void OnEmcy(uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept
override;
389 using FiberDriver::FiberDriver;
402 ev_exec_t * exec, canopen::AsyncMaster & master, uint8_t
id, std::string name, std::string eds,
404 : FiberDriver(exec, master, id),
411 dictionary_ = std::make_unique<DriverDictionary>(eds.c_str());
413 if (stat(bin.c_str(), &buffer) == 0)
415 co_unsigned16_t * a = NULL;
416 co_unsigned16_t * b = NULL;
417 dictionary_->readDCF(a, b, bin.c_str());
419 pdo_map_ = dictionary_->createPDOMapping();
437 template <
typename T>
440 std::unique_lock<std::mutex> lck(sdo_mutex);
447 auto prom = std::make_shared<std::promise<bool>>();
448 lely::COSub * sub = this->dictionary_->find(idx, subidx);
451 std::cout <<
"async_sdo_write_typed: id=" << (
unsigned int)this->get_id() <<
" index=0x"
452 << std::hex << (
unsigned int)idx <<
" subindex=" << (
unsigned int)subidx
453 <<
" object does not exist" << std::endl;
454 prom->set_value(
false);
455 this->running =
false;
456 this->sdo_cond.notify_one();
457 return prom->get_future();
462 [
this, value, prom](uint8_t
id, uint16_t idx, uint8_t subidx, ::std::error_code ec)
mutable
467 lely::canopen::make_sdo_exception_ptr(
id, idx, subidx, ec,
"AsyncDownload"));
471 std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
472 this->dictionary_->setVal<T>(idx, subidx, value);
473 prom->set_value(
true);
475 std::unique_lock<std::mutex> lck(this->sdo_mutex);
476 this->running =
false;
477 this->sdo_cond.notify_one();
480 return prom->get_future();
483 template <
typename T>
485 uint16_t idx, uint8_t subidx, T value, std::chrono::milliseconds timeout)
487 auto fut = async_sdo_write_typed(idx, subidx, value);
488 auto wait_res = fut.wait_for(timeout);
489 if (wait_res == std::future_status::timeout)
491 std::cout <<
"sync_sdo_write_typed: id=" << (
unsigned int)this->get_id() <<
" index=0x"
492 << std::hex << (
unsigned int)idx <<
" subindex=" << (
unsigned int)subidx
493 <<
" timed out." << std::endl;
501 catch (std::exception & e)
503 RCLCPP_ERROR(rclcpp::get_logger(name_), e.what());
523 template <
typename T>
526 std::unique_lock<std::mutex> lck(sdo_mutex);
533 auto prom = std::make_shared<std::promise<T>>();
534 lely::COSub * sub = this->dictionary_->find(idx, subidx);
537 std::cout <<
"async_sdo_read: id=" << (
unsigned int)this->get_id() <<
" index=0x" << std::hex
538 << (
unsigned int)idx <<
" subindex=" << (
unsigned int)subidx
539 <<
" object does not exist" << std::endl;
542 throw lely::canopen::SdoError(this->get_id(), idx, subidx, lely::canopen::SdoErrc::NO_OBJ);
546 prom->set_exception(std::current_exception());
548 this->running =
false;
549 this->sdo_cond.notify_one();
550 return prom->get_future();
554 [
this, prom](uint8_t
id, uint16_t idx, uint8_t subidx, ::std::error_code ec, T value)
mutable
559 lely::canopen::make_sdo_exception_ptr(
id, idx, subidx, ec,
"AsyncUpload"));
563 std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
564 this->dictionary_->setVal<T>(idx, subidx, value);
565 prom->set_value(value);
567 std::unique_lock<std::mutex> lck(this->sdo_mutex);
568 this->running =
false;
569 this->sdo_cond.notify_one();
572 return prom->get_future();
575 template <
typename T>
577 uint16_t idx, uint8_t subidx, T & value, std::chrono::milliseconds timeout)
579 auto fut = async_sdo_read_typed<T>(idx, subidx);
580 auto wait_res = fut.wait_for(timeout);
581 if (wait_res == std::future_status::timeout)
583 std::cout <<
"sync_sdo_read_typed: id=" << (
unsigned int)this->get_id() <<
" index=0x"
584 << std::hex << (
unsigned int)idx <<
" subindex=" << (
unsigned int)subidx
585 <<
" timed out." << std::endl;
594 catch (std::exception & e)
596 RCLCPP_ERROR(rclcpp::get_logger(name_), e.what());
675 std::unique_lock<std::mutex> lck(boot_mtex);
677 if ((boot_status != 0) && (boot_status !=
'L'))
691 on_sync_function_ = on_sync_function;
714 template <
typename T>
718 std::memcpy(&value, &data.
data_,
sizeof(value));
722 [
this, value](uint8_t
id, uint16_t idx, uint8_t subidx, ::std::error_code ec)
mutable
726 this->sdo_write_data_promise->set_exception(
727 lely::canopen::make_sdo_exception_ptr(id, idx, subidx, ec,
"AsyncDownload"));
731 std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
732 this->dictionary_->setVal<T>(idx, subidx, value);
733 this->sdo_write_data_promise->set_value(true);
735 std::unique_lock<std::mutex> lck(this->sdo_mutex);
736 this->running =
false;
737 this->sdo_cond.notify_one();
742 template <
typename T>
747 [
this](uint8_t
id, uint16_t idx, uint8_t subidx, ::std::error_code ec, T value)
mutable
751 this->sdo_read_data_promise->set_exception(
752 lely::canopen::make_sdo_exception_ptr(id, idx, subidx, ec,
"AsyncUpload"));
756 std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
757 this->dictionary_->setVal<T>(idx, subidx, value);
758 COData d = {idx, subidx, 0};
759 std::memcpy(&d.data_, &value,
sizeof(T));
760 this->sdo_read_data_promise->set_value(d);
762 std::unique_lock<std::mutex> lck(this->sdo_mutex);
763 this->running =
false;
764 this->sdo_cond.notify_one();
769 template <
typename T>
773 bool is_tpdo =
false;
774 if (this->pdo_map_->find(index) != this->pdo_map_->end())
776 auto object = this->pdo_map_->at(index);
777 if (
object.find(subindex) !=
object.end())
779 auto entry =
object.at(subindex);
780 is_tpdo = entry.is_tpdo;
785 if (sync_sdo_read_typed<T>(index, subindex, value, std::chrono::milliseconds(20)))
791 std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
792 if (
typeid(T) ==
typeid(uint8_t))
794 value = this->dictionary_->getVal<CO_DEFTYPE_UNSIGNED8>(index, subindex);
796 if (
typeid(T) ==
typeid(uint16_t))
798 value = this->dictionary_->getVal<CO_DEFTYPE_UNSIGNED16>(index, subindex);
800 if (
typeid(T) ==
typeid(uint32_t))
802 value = this->dictionary_->getVal<CO_DEFTYPE_UNSIGNED32>(index, subindex);
804 if (
typeid(T) ==
typeid(int8_t))
806 value = this->dictionary_->getVal<CO_DEFTYPE_INTEGER8>(index, subindex);
808 if (
typeid(T) ==
typeid(int16_t))
810 value = this->dictionary_->getVal<CO_DEFTYPE_INTEGER16>(index, subindex);
812 if (
typeid(T) ==
typeid(int32_t))
814 value = this->dictionary_->getVal<CO_DEFTYPE_INTEGER32>(index, subindex);
820 template <
typename T>
823 bool is_rpdo =
false;
824 if (this->pdo_map_->find(index) != this->pdo_map_->end())
826 auto object = this->pdo_map_->at(index);
827 if (
object.find(subindex) !=
object.end())
829 auto entry =
object.at(subindex);
830 is_rpdo = entry.is_rpdo;
835 std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
836 this->dictionary_->setVal<T>(index, subindex, value);
837 this->tpdo_mapped[index][subindex] = value;
838 this->tpdo_mapped[index][subindex].WriteEvent();
842 sync_sdo_write_typed(index, subindex, value, std::chrono::milliseconds(20));
Definition: lely_driver_bridge.hpp:59
~DriverDictionary()
Definition: lely_driver_bridge.hpp:62
DriverDictionary(std::string eds_file)
Definition: lely_driver_bridge.hpp:61
bool checkObjTPDO(uint16_t idx, uint8_t subidx)
Definition: lely_driver_bridge.hpp:187
bool checkObjInPDO(uint8_t pdo, uint16_t mapping_idx, uint16_t idx, uint8_t subindex)
Definition: lely_driver_bridge.hpp:201
std::shared_ptr< PDOMap > createPDOMapping()
Definition: lely_driver_bridge.hpp:67
void fetchTPDO(std::shared_ptr< PDOMap > map)
Definition: lely_driver_bridge.hpp:141
void fetchRPDO(std::shared_ptr< PDOMap > map)
Definition: lely_driver_bridge.hpp:111
bool checkObjRPDO(uint16_t idx, uint8_t subidx)
Definition: lely_driver_bridge.hpp:173
Lely Driver Bridge.
Definition: lely_driver_bridge.hpp:276
std::atomic< bool > emcy_is_set
Definition: lely_driver_bridge.hpp:303
std::mutex sdo_mutex
Definition: lely_driver_bridge.hpp:286
void universal_set_value(uint16_t index, uint8_t subindex, T value)
Definition: lely_driver_bridge.hpp:821
bool is_booted()
Indicates if Device is booted.
Definition: lely_driver_bridge.hpp:712
std::mutex boot_mtex
Definition: lely_driver_bridge.hpp:313
std::shared_ptr< SafeQueue< COEmcy > > get_emcy_queue()
Asynchronous request for EMCY.
bool sync_sdo_write_typed(uint16_t idx, uint8_t subidx, T value, std::chrono::milliseconds timeout)
Definition: lely_driver_bridge.hpp:484
std::promise< COData > rpdo_promise
Definition: lely_driver_bridge.hpp:296
bool running
Definition: lely_driver_bridge.hpp:287
bool sync_sdo_read_typed(uint16_t idx, uint8_t subidx, T &value, std::chrono::milliseconds timeout)
Definition: lely_driver_bridge.hpp:576
std::shared_ptr< std::promise< bool > > sdo_write_data_promise
Definition: lely_driver_bridge.hpp:285
std::future< canopen::NmtState > async_request_nmt()
Asynchronous request for NMT.
std::shared_ptr< PDOMap > pdo_map_
Definition: lely_driver_bridge.hpp:281
std::unique_ptr< DriverDictionary > dictionary_
Definition: lely_driver_bridge.hpp:279
std::atomic< bool > rpdo_is_set
Definition: lely_driver_bridge.hpp:297
std::condition_variable sdo_cond
Definition: lely_driver_bridge.hpp:288
void unset_sync_function()
Definition: lely_driver_bridge.hpp:694
std::mutex emcy_mtex
Definition: lely_driver_bridge.hpp:304
void OnRpdoWrite(uint16_t idx, uint8_t subidx) noexcept override
OnRpdoWrite Callback.
virtual void OnBoot(canopen::NmtState st, char es, const ::std::string &what) noexcept override
OnBoot Callback This callback is called when the Boot process of the slave that was initiated by the ...
void nmt_command(canopen::NmtCommand command)
Executes a NMT Command.
void set_sync_function(std::function< void()> on_sync_function)
Definition: lely_driver_bridge.hpp:689
std::string boot_what
Definition: lely_driver_bridge.hpp:310
std::mutex nmt_mtex
Definition: lely_driver_bridge.hpp:293
std::promise< canopen::NmtState > nmt_state_promise
Definition: lely_driver_bridge.hpp:291
void submit_read(COData data)
Definition: lely_driver_bridge.hpp:743
std::atomic< bool > nmt_state_is_set
Definition: lely_driver_bridge.hpp:292
std::function< void()> on_sync_function_
Definition: lely_driver_bridge.hpp:318
uint8_t get_id()
Get the nodeid.
void OnEmcy(uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept override
void submit_write(COData data)
Definition: lely_driver_bridge.hpp:715
std::future< bool > async_sdo_write(COData data)
Asynchronous SDO Write.
std::shared_ptr< SafeQueue< COData > > get_rpdo_queue()
Asynchronous request for RPDO.
const T universal_get_value(uint16_t index, uint8_t subindex)
Definition: lely_driver_bridge.hpp:770
std::shared_ptr< SafeQueue< COData > > rpdo_queue
Definition: lely_driver_bridge.hpp:299
std::future< bool > async_sdo_write_typed(uint16_t idx, uint8_t subidx, T value)
Definition: lely_driver_bridge.hpp:438
std::mutex pdo_mtex
Definition: lely_driver_bridge.hpp:298
void Boot()
Request master to boot device.
Definition: lely_driver_bridge.hpp:700
std::future< COData > async_sdo_read(COData data)
Aynchronous SDO Read.
bool wait_for_boot()
Wait for device to be booted.
Definition: lely_driver_bridge.hpp:669
std::atomic< bool > booted
Definition: lely_driver_bridge.hpp:308
LelyDriverBridge(ev_exec_t *exec, canopen::AsyncMaster &master, uint8_t id, std::string name, std::string eds, std::string bin)
Construct a new Lely Bridge object.
Definition: lely_driver_bridge.hpp:401
std::shared_ptr< std::promise< COData > > sdo_read_data_promise
Definition: lely_driver_bridge.hpp:284
std::promise< COEmcy > emcy_promise
Definition: lely_driver_bridge.hpp:302
std::condition_variable boot_cond
Definition: lely_driver_bridge.hpp:312
void tpdo_transmit(COData data)
Executes a TPDO transmission.
char boot_status
Definition: lely_driver_bridge.hpp:309
std::shared_ptr< SafeQueue< COEmcy > > emcy_queue
Definition: lely_driver_bridge.hpp:305
void OnSync(uint8_t cnt, const time_point &t) noexcept override
Definition: lely_driver_bridge.hpp:330
std::mutex dictionary_mutex_
Definition: lely_driver_bridge.hpp:280
std::future< T > async_sdo_read_typed(uint16_t idx, uint8_t subidx)
Definition: lely_driver_bridge.hpp:524
canopen::NmtState boot_state
Definition: lely_driver_bridge.hpp:311
uint8_t nodeid
Definition: lely_driver_bridge.hpp:315
std::string name_
Definition: lely_driver_bridge.hpp:316
void OnState(canopen::NmtState state) noexcept override
OnState Callback.
Thread Safe Queue for CANOpen Data Exchange.
Definition: exchange.hpp:49
Definition: configuration_manager.hpp:28
std::map< uint16_t, std::map< uint8_t, pdo_mapping > > PDOMap
Definition: lely_driver_bridge.hpp:57
LelyBridgeErrc
Definition: lely_driver_bridge.hpp:229
@ InconsistentProgramDownload
@ ConfigurationDownloadFailed
@ StartErrorControlFailed
@ NmtSlaveInitiallyOperational
Definition: lely_driver_bridge.hpp:255
std::error_code make_error_code(ros2_canopen::LelyBridgeErrc)
Definition: exchange.hpp:26
uint32_t data_
Definition: exchange.hpp:30
uint8_t subindex_
Definition: exchange.hpp:29
uint16_t index_
Definition: exchange.hpp:28
Definition: exchange.hpp:34
Definition: lely_driver_bridge.hpp:248
const char * name() const noexcept override
Definition: lely_driver_bridge.hpp:52
bool is_rpdo
Definition: lely_driver_bridge.hpp:54
bool is_tpdo
Definition: lely_driver_bridge.hpp:53