ros2_canopen  master
C++ ROS CANopen Library
lely_driver_bridge.hpp
Go to the documentation of this file.
1 // Copyright 2022 Christoph Hellmann Santos
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef CANOPEN_BASE_DRIVER__LELY_BRIDGE_HPP_
16 #define CANOPEN_BASE_DRIVER__LELY_BRIDGE_HPP_
17 
18 #include <sys/stat.h>
19 
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>
28 
29 #include <atomic>
30 #include <condition_variable>
31 #include <future>
32 #include <memory>
33 #include <mutex>
34 #include <rclcpp/rclcpp.hpp>
35 #include <string>
36 #include <system_error>
37 #include <thread>
38 #include <vector>
39 
40 #include <boost/lockfree/queue.hpp>
41 #include <boost/optional.hpp>
42 #include <boost/thread.hpp>
43 
45 
46 using namespace std::chrono_literals;
47 using namespace lely;
48 
49 namespace ros2_canopen
50 {
52 {
53  bool is_tpdo;
54  bool is_rpdo;
55 };
56 
57 typedef std::map<uint16_t, std::map<uint8_t, pdo_mapping>> PDOMap;
58 class DriverDictionary : public lely::CODev
59 {
60 public:
61  DriverDictionary(std::string eds_file) : lely::CODev(eds_file.c_str()) {}
63  {
64  // lely::CODev::~CODev();
65  }
66 
67  std::shared_ptr<PDOMap> createPDOMapping()
68  {
69  std::shared_ptr<PDOMap> pdo_map = std::make_shared<PDOMap>();
70  fetchRPDO(pdo_map);
71  fetchTPDO(pdo_map);
72  return pdo_map;
73  // COObj * first = co_dev_first_obj((lely::CODev *)this);
74  // COObj * last = co_dev_last_obj((lely::CODev *)this);
75  // if (first == nullptr || last == nullptr)
76  // {
77  // std::cout << "No objects found in dictionary" << std::endl;
78  // return pdo_map;
79  // }
80  // COObj * current = first;
81  // while (current != last)
82  // {
83  // uint16_t index = co_obj_get_idx(current);
84  // auto subids = current->getSubidx();
85  // bool created = false;
86  // for (auto subid : subids)
87  // {
88  // bool is_rpdo = checkObjRPDO(index, subid);
89  // bool is_tpdo = checkObjTPDO(index, subid);
90  // std::cout << "Found subobject: index=" << std::hex << (int)index
91  // << " subindex=" << (int)subid << (is_rpdo ? " rpdo" : "")
92  // << (is_tpdo ? " tpdo" : "") << std::endl;
93  // if (is_rpdo || is_tpdo)
94  // {
95  // pdo_mapping mapping;
96  // mapping.is_rpdo = is_rpdo;
97  // mapping.is_tpdo = is_tpdo;
98  // if (!created)
99  // {
100  // pdo_map->emplace(index, std::map<uint8_t, pdo_mapping>());
101  // created = true;
102  // }
103  // (*pdo_map)[index].emplace(subid, mapping);
104  // }
105  // }
106  // current = co_obj_next(current);
107  // }
108  // return pdo_map;
109  }
110 
111  void fetchRPDO(std::shared_ptr<PDOMap> map)
112  {
113  for (int index = 0; index < 256; index++)
114  {
115  for (int subindex = 1; subindex < 9; subindex++)
116  {
117  auto obj = find(0x1600 + index, subindex);
118  if (obj == nullptr)
119  {
120  continue;
121  }
122  uint32_t data;
123  {
124  data = obj->getVal<CO_DEFTYPE_UNSIGNED32>();
125  }
126  uint8_t tmps = (data >> 8) & 0xFF;
127  uint16_t tmpi = (data >> 16) & 0xFFFF;
128  if (tmpi == 0U)
129  {
130  continue;
131  }
132  pdo_mapping mapping;
133  mapping.is_rpdo = true;
134  mapping.is_tpdo = false;
135  (*map)[tmpi][tmps] = mapping;
136  std::cout << "Found rpdo mapped object: index=" << std::hex << (int)tmpi
137  << " subindex=" << (int)tmps << std::endl;
138  }
139  }
140  }
141  void fetchTPDO(std::shared_ptr<PDOMap> map)
142  {
143  for (int index = 0; index < 256; index++)
144  {
145  for (int subindex = 1; subindex < 9; subindex++)
146  {
147  auto obj = find(0x1A00 + index, subindex);
148  if (obj == nullptr)
149  {
150  continue;
151  }
152  uint32_t data;
153  {
154  data = obj->getVal<CO_DEFTYPE_UNSIGNED32>();
155  }
156  uint8_t tmps = (data >> 8) & 0xFF;
157  uint16_t tmpi = (data >> 16) & 0xFFFF;
158  if (tmpi == 0U)
159  {
160  continue;
161  }
162 
163  pdo_mapping mapping;
164  mapping.is_rpdo = false;
165  mapping.is_tpdo = true;
166  (*map)[tmpi][tmps] = mapping;
167  std::cout << "Found tpdo mapped object: index=" << std::hex << (int)tmpi
168  << " subindex=" << (int)tmps << std::endl;
169  }
170  }
171  }
172 
173  bool checkObjRPDO(uint16_t idx, uint8_t subidx)
174  {
175  // std::cout << "Checking for rpo mapping of object: index=" << std::hex << (int)idx
176  // << " subindex=" << (int)subidx << std::endl;
177  for (int i = 0; i < 256; i++)
178  {
179  if (this->checkObjInPDO(i, 0x1600, idx, subidx))
180  {
181  return true;
182  }
183  }
184  return false;
185  }
186 
187  bool checkObjTPDO(uint16_t idx, uint8_t subidx)
188  {
189  // std::cout << "Checking for rpo mapping of object: index=" << std::hex << (int)idx
190  // << " subindex=" << (int)subidx << std::endl;
191  for (int i = 0; i < 256; i++)
192  {
193  if (this->checkObjInPDO(i, 0x1A00, idx, subidx))
194  {
195  return true;
196  }
197  }
198  return false;
199  }
200 
201  bool checkObjInPDO(uint8_t pdo, uint16_t mapping_idx, uint16_t idx, uint8_t subindex)
202  {
203  for (int i = 1; i < 9; i++)
204  {
205  auto obj = find(mapping_idx + pdo, i);
206  if (obj == nullptr)
207  {
208  return false;
209  }
210  uint32_t data;
211  {
212  data = obj->getVal<CO_DEFTYPE_UNSIGNED32>();
213  }
214  uint8_t tmps = (data >> 8) & 0xFF;
215  uint16_t tmpi = (data >> 16) & 0xFFFF;
216 
217  if (tmps == subindex && tmpi == idx)
218  {
219  std::cout << "Found object in pdo: " << (int)pdo << std::endl;
220  return true;
221  }
222  }
223 
224  return false;
225  }
226 };
227 
228 enum class LelyBridgeErrc
229 {
230  NotListedDevice = 'A',
232  DeviceTypeDifference = 'C',
233  VendorIdDifference = 'D',
234  HeartbeatIssue = 'E',
235  NodeGuardingIssue = 'F',
242  ProductCodeDifference = 'M',
245 };
246 
247 struct LelyBridgeErrCategory : std::error_category
248 {
249  const char * name() const noexcept override;
250  std::string message(int ev) const override;
251 };
252 } // namespace ros2_canopen
253 
254 namespace std
255 {
256 template <>
257 struct is_error_code_enum<ros2_canopen::LelyBridgeErrc> : true_type
258 {
259 };
261 } // namespace std
262 
263 namespace ros2_canopen
264 {
275 class LelyDriverBridge : public canopen::FiberDriver
276 {
277 protected:
278  // Dictionary for driver based on DCF and BIN files.
279  std::unique_ptr<DriverDictionary> dictionary_;
280  std::mutex dictionary_mutex_;
281  std::shared_ptr<PDOMap> pdo_map_;
282 
283  // SDO Read synchronisation items
284  std::shared_ptr<std::promise<COData>> sdo_read_data_promise;
285  std::shared_ptr<std::promise<bool>> sdo_write_data_promise;
286  std::mutex sdo_mutex;
287  bool running;
288  std::condition_variable sdo_cond;
289 
290  // NMT synchronisation items
291  std::promise<canopen::NmtState> nmt_state_promise;
292  std::atomic<bool> nmt_state_is_set;
293  std::mutex nmt_mtex;
294 
295  // RPDO synchronisation items
296  std::promise<COData> rpdo_promise;
297  std::atomic<bool> rpdo_is_set;
298  std::mutex pdo_mtex;
299  std::shared_ptr<SafeQueue<COData>> rpdo_queue;
300 
301  // EMCY synchronisation items
302  std::promise<COEmcy> emcy_promise;
303  std::atomic<bool> emcy_is_set;
304  std::mutex emcy_mtex;
305  std::shared_ptr<SafeQueue<COEmcy>> emcy_queue;
306 
307  // BOOT synchronisation items
308  std::atomic<bool> booted;
310  std::string boot_what;
311  canopen::NmtState boot_state;
312  std::condition_variable boot_cond;
313  std::mutex boot_mtex;
314 
315  uint8_t nodeid;
316  std::string name_;
317 
318  std::function<void()> on_sync_function_;
319 
320  // void set_sync_function(std::function<void()> on_sync_function)
321  // {
322  // on_sync_function_ = on_sync_function;
323  // }
324 
325  // void unset_sync_function()
326  // {
327  // on_sync_function_ = std::function<void()>();
328  // }
329 
330  void OnSync(uint8_t cnt, const time_point & t) noexcept override
331  {
332  if (on_sync_function_ != nullptr)
333  {
334  try
335  {
336  on_sync_function_();
337  }
338  catch (...)
339  {
340  }
341  }
342  }
343 
352  void OnState(canopen::NmtState state) noexcept override;
353 
364  virtual void OnBoot(canopen::NmtState st, char es, const ::std::string & what) noexcept override;
365 
376  void OnRpdoWrite(uint16_t idx, uint8_t subidx) noexcept override;
377 
386  void OnEmcy(uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept override;
387 
388 public:
389  using FiberDriver::FiberDriver;
390 
402  ev_exec_t * exec, canopen::AsyncMaster & master, uint8_t id, std::string name, std::string eds,
403  std::string bin)
404  : FiberDriver(exec, master, id),
405  rpdo_queue(new SafeQueue<COData>()),
406  emcy_queue(new SafeQueue<COEmcy>())
407  {
408  nodeid = id;
409  running = false;
410  name_ = name;
411  dictionary_ = std::make_unique<DriverDictionary>(eds.c_str());
412  struct stat buffer;
413  if (stat(bin.c_str(), &buffer) == 0)
414  {
415  co_unsigned16_t * a = NULL;
416  co_unsigned16_t * b = NULL;
417  dictionary_->readDCF(a, b, bin.c_str());
418  }
419  pdo_map_ = dictionary_->createPDOMapping();
420  }
421 
435  std::future<bool> async_sdo_write(COData data);
436 
437  template <typename T>
438  std::future<bool> async_sdo_write_typed(uint16_t idx, uint8_t subidx, T value)
439  {
440  std::unique_lock<std::mutex> lck(sdo_mutex);
441  if (running)
442  {
443  sdo_cond.wait(lck);
444  }
445  running = true;
446 
447  auto prom = std::make_shared<std::promise<bool>>();
448  lely::COSub * sub = this->dictionary_->find(idx, subidx);
449  if (sub == nullptr)
450  {
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();
458  }
459 
460  this->SubmitWrite(
461  idx, subidx, value,
462  [this, value, prom](uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec) mutable
463  {
464  if (ec)
465  {
466  prom->set_exception(
467  lely::canopen::make_sdo_exception_ptr(id, idx, subidx, ec, "AsyncDownload"));
468  }
469  else
470  {
471  std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
472  this->dictionary_->setVal<T>(idx, subidx, value);
473  prom->set_value(true);
474  }
475  std::unique_lock<std::mutex> lck(this->sdo_mutex);
476  this->running = false;
477  this->sdo_cond.notify_one();
478  },
479  20ms);
480  return prom->get_future();
481  }
482 
483  template <typename T>
485  uint16_t idx, uint8_t subidx, T value, std::chrono::milliseconds timeout)
486  {
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)
490  {
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;
494  return false;
495  }
496  bool res = false;
497  try
498  {
499  res = fut.get();
500  }
501  catch (std::exception & e)
502  {
503  RCLCPP_ERROR(rclcpp::get_logger(name_), e.what());
504  }
505  return res;
506  }
507 
521  std::future<COData> async_sdo_read(COData data);
522 
523  template <typename T>
524  std::future<T> async_sdo_read_typed(uint16_t idx, uint8_t subidx)
525  {
526  std::unique_lock<std::mutex> lck(sdo_mutex);
527  if (running)
528  {
529  sdo_cond.wait(lck);
530  }
531  running = true;
532 
533  auto prom = std::make_shared<std::promise<T>>();
534  lely::COSub * sub = this->dictionary_->find(idx, subidx);
535  if (sub == nullptr)
536  {
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;
540  try
541  {
542  throw lely::canopen::SdoError(this->get_id(), idx, subidx, lely::canopen::SdoErrc::NO_OBJ);
543  }
544  catch (...)
545  {
546  prom->set_exception(std::current_exception());
547  }
548  this->running = false;
549  this->sdo_cond.notify_one();
550  return prom->get_future();
551  }
552  this->SubmitRead<T>(
553  idx, subidx,
554  [this, prom](uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec, T value) mutable
555  {
556  if (ec)
557  {
558  prom->set_exception(
559  lely::canopen::make_sdo_exception_ptr(id, idx, subidx, ec, "AsyncUpload"));
560  }
561  else
562  {
563  std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
564  this->dictionary_->setVal<T>(idx, subidx, value);
565  prom->set_value(value);
566  }
567  std::unique_lock<std::mutex> lck(this->sdo_mutex);
568  this->running = false;
569  this->sdo_cond.notify_one();
570  },
571  20ms);
572  return prom->get_future();
573  }
574 
575  template <typename T>
577  uint16_t idx, uint8_t subidx, T & value, std::chrono::milliseconds timeout)
578  {
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)
582  {
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;
586  return false;
587  }
588  bool res = false;
589  try
590  {
591  value = fut.get();
592  res = true;
593  }
594  catch (std::exception & e)
595  {
596  RCLCPP_ERROR(rclcpp::get_logger(name_), e.what());
597  res = false;
598  }
599  return res;
600  }
601 
611  std::future<canopen::NmtState> async_request_nmt();
612 
624  std::shared_ptr<SafeQueue<COData>> get_rpdo_queue();
625 
633  std::shared_ptr<SafeQueue<COEmcy>> get_emcy_queue();
634 
644  void tpdo_transmit(COData data);
645 
654  void nmt_command(canopen::NmtCommand command);
655 
661  uint8_t get_id();
662 
670  {
671  if (booted.load())
672  {
673  return true;
674  }
675  std::unique_lock<std::mutex> lck(boot_mtex);
676  boot_cond.wait(lck);
677  if ((boot_status != 0) && (boot_status != 'L'))
678  {
679  throw std::system_error(boot_status, LelyBridgeErrCategory(), "Boot Issue");
680  }
681  else
682  {
683  booted.store(true);
684  return true;
685  }
686  return false;
687  }
688 
689  void set_sync_function(std::function<void()> on_sync_function)
690  {
691  on_sync_function_ = on_sync_function;
692  }
693 
694  void unset_sync_function() { on_sync_function_ = std::function<void()>(); }
695 
700  void Boot()
701  {
702  booted.store(false);
703  FiberDriver::Boot();
704  }
705 
712  bool is_booted() { return booted.load(); }
713 
714  template <typename T>
715  void submit_write(COData data)
716  {
717  T value = 0;
718  std::memcpy(&value, &data.data_, sizeof(value));
719 
720  this->SubmitWrite(
721  data.index_, data.subindex_, value,
722  [this, value](uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec) mutable
723  {
724  if (ec)
725  {
726  this->sdo_write_data_promise->set_exception(
727  lely::canopen::make_sdo_exception_ptr(id, idx, subidx, ec, "AsyncDownload"));
728  }
729  else
730  {
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);
734  }
735  std::unique_lock<std::mutex> lck(this->sdo_mutex);
736  this->running = false;
737  this->sdo_cond.notify_one();
738  },
739  20ms);
740  }
741 
742  template <typename T>
743  void submit_read(COData data)
744  {
745  this->SubmitRead<T>(
746  data.index_, data.subindex_,
747  [this](uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec, T value) mutable
748  {
749  if (ec)
750  {
751  this->sdo_read_data_promise->set_exception(
752  lely::canopen::make_sdo_exception_ptr(id, idx, subidx, ec, "AsyncUpload"));
753  }
754  else
755  {
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);
761  }
762  std::unique_lock<std::mutex> lck(this->sdo_mutex);
763  this->running = false;
764  this->sdo_cond.notify_one();
765  },
766  20ms);
767  }
768 
769  template <typename T>
770  const T universal_get_value(uint16_t index, uint8_t subindex)
771  {
772  T value = 0;
773  bool is_tpdo = false;
774  if (this->pdo_map_->find(index) != this->pdo_map_->end())
775  {
776  auto object = this->pdo_map_->at(index);
777  if (object.find(subindex) != object.end())
778  {
779  auto entry = object.at(subindex);
780  is_tpdo = entry.is_tpdo;
781  }
782  }
783  if (!is_tpdo)
784  {
785  if (sync_sdo_read_typed<T>(index, subindex, value, std::chrono::milliseconds(20)))
786  {
787  return value;
788  }
789  }
790 
791  std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
792  if (typeid(T) == typeid(uint8_t))
793  {
794  value = this->dictionary_->getVal<CO_DEFTYPE_UNSIGNED8>(index, subindex);
795  }
796  if (typeid(T) == typeid(uint16_t))
797  {
798  value = this->dictionary_->getVal<CO_DEFTYPE_UNSIGNED16>(index, subindex);
799  }
800  if (typeid(T) == typeid(uint32_t))
801  {
802  value = this->dictionary_->getVal<CO_DEFTYPE_UNSIGNED32>(index, subindex);
803  }
804  if (typeid(T) == typeid(int8_t))
805  {
806  value = this->dictionary_->getVal<CO_DEFTYPE_INTEGER8>(index, subindex);
807  }
808  if (typeid(T) == typeid(int16_t))
809  {
810  value = this->dictionary_->getVal<CO_DEFTYPE_INTEGER16>(index, subindex);
811  }
812  if (typeid(T) == typeid(int32_t))
813  {
814  value = this->dictionary_->getVal<CO_DEFTYPE_INTEGER32>(index, subindex);
815  }
816 
817  return value;
818  }
819 
820  template <typename T>
821  void universal_set_value(uint16_t index, uint8_t subindex, T value)
822  {
823  bool is_rpdo = false;
824  if (this->pdo_map_->find(index) != this->pdo_map_->end())
825  {
826  auto object = this->pdo_map_->at(index);
827  if (object.find(subindex) != object.end())
828  {
829  auto entry = object.at(subindex);
830  is_rpdo = entry.is_rpdo;
831  }
832  }
833  if (is_rpdo)
834  {
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();
839  }
840  else
841  {
842  sync_sdo_write_typed(index, subindex, value, std::chrono::milliseconds(20));
843  }
844  }
845 };
846 
847 } // namespace ros2_canopen
848 
849 #endif // CANOPEN_BASE_DRIVER__LELY_BRIDGE_HPP_
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
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