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::chrono::milliseconds sdo_timeout;
319 
320  std::function<void()> on_sync_function_;
321 
322  // void set_sync_function(std::function<void()> on_sync_function)
323  // {
324  // on_sync_function_ = on_sync_function;
325  // }
326 
327  // void unset_sync_function()
328  // {
329  // on_sync_function_ = std::function<void()>();
330  // }
331 
332  void OnSync(uint8_t cnt, const time_point & t) noexcept override
333  {
334  if (on_sync_function_ != nullptr)
335  {
336  try
337  {
338  on_sync_function_();
339  }
340  catch (...)
341  {
342  }
343  }
344  }
345 
354  void OnState(canopen::NmtState state) noexcept override;
355 
366  virtual void OnBoot(canopen::NmtState st, char es, const ::std::string & what) noexcept override;
367 
378  void OnRpdoWrite(uint16_t idx, uint8_t subidx) noexcept override;
379 
388  void OnEmcy(uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept override;
389 
390 public:
391  using FiberDriver::FiberDriver;
392 
405  ev_exec_t * exec, canopen::AsyncMaster & master, uint8_t id, std::string name, std::string eds,
406  std::string bin, std::chrono::milliseconds timeout = 20ms)
407  : FiberDriver(exec, master, id),
408  rpdo_queue(new SafeQueue<COData>()),
409  emcy_queue(new SafeQueue<COEmcy>())
410  {
411  nodeid = id;
412  running = false;
413  name_ = name;
414  dictionary_ = std::make_unique<DriverDictionary>(eds.c_str());
415  struct stat buffer;
416  if (stat(bin.c_str(), &buffer) == 0)
417  {
418  co_unsigned16_t * a = NULL;
419  co_unsigned16_t * b = NULL;
420  dictionary_->readDCF(a, b, bin.c_str());
421  }
422  pdo_map_ = dictionary_->createPDOMapping();
423  sdo_timeout = timeout;
424  }
425 
439  std::future<bool> async_sdo_write(COData data);
440 
441  template <typename T>
442  std::future<bool> async_sdo_write_typed(uint16_t idx, uint8_t subidx, T value)
443  {
444  std::unique_lock<std::mutex> lck(sdo_mutex);
445  if (running)
446  {
447  sdo_cond.wait(lck);
448  }
449  running = true;
450 
451  auto prom = std::make_shared<std::promise<bool>>();
452  lely::COSub * sub = this->dictionary_->find(idx, subidx);
453  if (sub == nullptr)
454  {
455  std::cout << "async_sdo_write_typed: id=" << (unsigned int)this->get_id() << " index=0x"
456  << std::hex << (unsigned int)idx << " subindex=" << (unsigned int)subidx
457  << " object does not exist" << std::endl;
458  prom->set_value(false);
459  this->running = false;
460  this->sdo_cond.notify_one();
461  return prom->get_future();
462  }
463 
464  this->SubmitWrite(
465  idx, subidx, value,
466  [this, value, prom](uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec) mutable
467  {
468  if (ec)
469  {
470  prom->set_exception(
471  lely::canopen::make_sdo_exception_ptr(id, idx, subidx, ec, "AsyncDownload"));
472  }
473  else
474  {
475  std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
476  this->dictionary_->setVal<T>(idx, subidx, value);
477  prom->set_value(true);
478  }
479  std::unique_lock<std::mutex> lck(this->sdo_mutex);
480  this->running = false;
481  this->sdo_cond.notify_one();
482  },
483  this->sdo_timeout);
484  return prom->get_future();
485  }
486 
487  template <typename T>
489  uint16_t idx, uint8_t subidx, T value, std::chrono::milliseconds timeout)
490  {
491  auto fut = async_sdo_write_typed(idx, subidx, value);
492  auto wait_res = fut.wait_for(timeout);
493  if (wait_res == std::future_status::timeout)
494  {
495  std::cout << "sync_sdo_write_typed: id=" << (unsigned int)this->get_id() << " index=0x"
496  << std::hex << (unsigned int)idx << " subindex=" << (unsigned int)subidx
497  << " timed out." << std::endl;
498  return false;
499  }
500  bool res = false;
501  try
502  {
503  res = fut.get();
504  }
505  catch (std::exception & e)
506  {
507  RCLCPP_ERROR(rclcpp::get_logger(name_), e.what());
508  }
509  return res;
510  }
511 
525  std::future<COData> async_sdo_read(COData data);
526 
527  template <typename T>
528  std::future<T> async_sdo_read_typed(uint16_t idx, uint8_t subidx)
529  {
530  std::unique_lock<std::mutex> lck(sdo_mutex);
531  if (running)
532  {
533  sdo_cond.wait(lck);
534  }
535  running = true;
536 
537  auto prom = std::make_shared<std::promise<T>>();
538  lely::COSub * sub = this->dictionary_->find(idx, subidx);
539  if (sub == nullptr)
540  {
541  std::cout << "async_sdo_read: id=" << (unsigned int)this->get_id() << " index=0x" << std::hex
542  << (unsigned int)idx << " subindex=" << (unsigned int)subidx
543  << " object does not exist" << std::endl;
544  try
545  {
546  throw lely::canopen::SdoError(this->get_id(), idx, subidx, lely::canopen::SdoErrc::NO_OBJ);
547  }
548  catch (...)
549  {
550  prom->set_exception(std::current_exception());
551  }
552  this->running = false;
553  this->sdo_cond.notify_one();
554  return prom->get_future();
555  }
556  this->SubmitRead<T>(
557  idx, subidx,
558  [this, prom](uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec, T value) mutable
559  {
560  if (ec)
561  {
562  prom->set_exception(
563  lely::canopen::make_sdo_exception_ptr(id, idx, subidx, ec, "AsyncUpload"));
564  }
565  else
566  {
567  std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
568  this->dictionary_->setVal<T>(idx, subidx, value);
569  prom->set_value(value);
570  }
571  std::unique_lock<std::mutex> lck(this->sdo_mutex);
572  this->running = false;
573  this->sdo_cond.notify_one();
574  },
575  this->sdo_timeout);
576  return prom->get_future();
577  }
578 
579  template <typename T>
581  uint16_t idx, uint8_t subidx, T & value, std::chrono::milliseconds timeout)
582  {
583  auto fut = async_sdo_read_typed<T>(idx, subidx);
584  auto wait_res = fut.wait_for(timeout);
585  if (wait_res == std::future_status::timeout)
586  {
587  std::cout << "sync_sdo_read_typed: id=" << (unsigned int)this->get_id() << " index=0x"
588  << std::hex << (unsigned int)idx << " subindex=" << (unsigned int)subidx
589  << " timed out." << std::endl;
590  return false;
591  }
592  bool res = false;
593  try
594  {
595  value = fut.get();
596  res = true;
597  }
598  catch (std::exception & e)
599  {
600  RCLCPP_ERROR(rclcpp::get_logger(name_), e.what());
601  res = false;
602  }
603  return res;
604  }
605 
615  std::future<canopen::NmtState> async_request_nmt();
616 
628  std::shared_ptr<SafeQueue<COData>> get_rpdo_queue();
629 
637  std::shared_ptr<SafeQueue<COEmcy>> get_emcy_queue();
638 
648  void tpdo_transmit(COData data);
649 
658  void nmt_command(canopen::NmtCommand command);
659 
665  uint8_t get_id();
666 
674  {
675  if (booted.load())
676  {
677  return true;
678  }
679  std::unique_lock<std::mutex> lck(boot_mtex);
680  boot_cond.wait(lck);
681  if ((boot_status != 0) && (boot_status != 'L'))
682  {
683  throw std::system_error(boot_status, LelyBridgeErrCategory(), "Boot Issue");
684  }
685  else
686  {
687  booted.store(true);
688  return true;
689  }
690  return false;
691  }
692 
693  void set_sync_function(std::function<void()> on_sync_function)
694  {
695  on_sync_function_ = on_sync_function;
696  }
697 
698  void unset_sync_function() { on_sync_function_ = std::function<void()>(); }
699 
704  void Boot()
705  {
706  booted.store(false);
707  FiberDriver::Boot();
708  }
709 
716  bool is_booted() { return booted.load(); }
717 
718  template <typename T>
719  void submit_write(COData data)
720  {
721  T value = 0;
722  std::memcpy(&value, &data.data_, sizeof(value));
723 
724  this->SubmitWrite(
725  data.index_, data.subindex_, value,
726  [this, value](uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec) mutable
727  {
728  if (ec)
729  {
730  this->sdo_write_data_promise->set_exception(
731  lely::canopen::make_sdo_exception_ptr(id, idx, subidx, ec, "AsyncDownload"));
732  }
733  else
734  {
735  std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
736  this->dictionary_->setVal<T>(idx, subidx, value);
737  this->sdo_write_data_promise->set_value(true);
738  }
739  std::unique_lock<std::mutex> lck(this->sdo_mutex);
740  this->running = false;
741  this->sdo_cond.notify_one();
742  },
743  this->sdo_timeout);
744  }
745 
746  template <typename T>
747  void submit_read(COData data)
748  {
749  this->SubmitRead<T>(
750  data.index_, data.subindex_,
751  [this](uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec, T value) mutable
752  {
753  if (ec)
754  {
755  this->sdo_read_data_promise->set_exception(
756  lely::canopen::make_sdo_exception_ptr(id, idx, subidx, ec, "AsyncUpload"));
757  }
758  else
759  {
760  std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
761  this->dictionary_->setVal<T>(idx, subidx, value);
762  COData d = {idx, subidx, 0};
763  std::memcpy(&d.data_, &value, sizeof(T));
764  this->sdo_read_data_promise->set_value(d);
765  }
766  std::unique_lock<std::mutex> lck(this->sdo_mutex);
767  this->running = false;
768  this->sdo_cond.notify_one();
769  },
770  this->sdo_timeout);
771  }
772 
773  template <typename T>
774  const T universal_get_value(uint16_t index, uint8_t subindex)
775  {
776  T value = 0;
777  bool is_tpdo = false;
778  if (this->pdo_map_->find(index) != this->pdo_map_->end())
779  {
780  auto object = this->pdo_map_->at(index);
781  if (object.find(subindex) != object.end())
782  {
783  auto entry = object.at(subindex);
784  is_tpdo = entry.is_tpdo;
785  }
786  }
787  if (!is_tpdo)
788  {
789  if (sync_sdo_read_typed<T>(index, subindex, value, this->sdo_timeout))
790  {
791  return value;
792  }
793  }
794 
795  std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
796  if (typeid(T) == typeid(uint8_t))
797  {
798  value = this->dictionary_->getVal<CO_DEFTYPE_UNSIGNED8>(index, subindex);
799  }
800  if (typeid(T) == typeid(uint16_t))
801  {
802  value = this->dictionary_->getVal<CO_DEFTYPE_UNSIGNED16>(index, subindex);
803  }
804  if (typeid(T) == typeid(uint32_t))
805  {
806  value = this->dictionary_->getVal<CO_DEFTYPE_UNSIGNED32>(index, subindex);
807  }
808  if (typeid(T) == typeid(int8_t))
809  {
810  value = this->dictionary_->getVal<CO_DEFTYPE_INTEGER8>(index, subindex);
811  }
812  if (typeid(T) == typeid(int16_t))
813  {
814  value = this->dictionary_->getVal<CO_DEFTYPE_INTEGER16>(index, subindex);
815  }
816  if (typeid(T) == typeid(int32_t))
817  {
818  value = this->dictionary_->getVal<CO_DEFTYPE_INTEGER32>(index, subindex);
819  }
820 
821  return value;
822  }
823 
824  template <typename T>
825  void universal_set_value(uint16_t index, uint8_t subindex, T value)
826  {
827  bool is_rpdo = false;
828  if (this->pdo_map_->find(index) != this->pdo_map_->end())
829  {
830  auto object = this->pdo_map_->at(index);
831  if (object.find(subindex) != object.end())
832  {
833  auto entry = object.at(subindex);
834  is_rpdo = entry.is_rpdo;
835  }
836  }
837  if (is_rpdo)
838  {
839  std::scoped_lock<std::mutex> lck(this->dictionary_mutex_);
840  this->dictionary_->setVal<T>(index, subindex, value);
841  this->tpdo_mapped[index][subindex] = value;
842  this->tpdo_mapped[index][subindex].WriteEvent();
843  }
844  else
845  {
846  sync_sdo_write_typed(index, subindex, value, this->sdo_timeout);
847  }
848  }
849 };
850 
851 } // namespace ros2_canopen
852 
853 #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:825
bool is_booted()
Indicates if Device is booted.
Definition: lely_driver_bridge.hpp:716
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:488
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:580
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:698
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:693
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
std::chrono::milliseconds sdo_timeout
Definition: lely_driver_bridge.hpp:318
void submit_read(COData data)
Definition: lely_driver_bridge.hpp:747
std::atomic< bool > nmt_state_is_set
Definition: lely_driver_bridge.hpp:292
std::function< void()> on_sync_function_
Definition: lely_driver_bridge.hpp:320
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:719
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:774
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:442
std::mutex pdo_mtex
Definition: lely_driver_bridge.hpp:298
void Boot()
Request master to boot device.
Definition: lely_driver_bridge.hpp:704
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:673
LelyDriverBridge(ev_exec_t *exec, canopen::AsyncMaster &master, uint8_t id, std::string name, std::string eds, std::string bin, std::chrono::milliseconds timeout=20ms)
Construct a new Lely Bridge object.
Definition: lely_driver_bridge.hpp:404
std::atomic< bool > booted
Definition: lely_driver_bridge.hpp:308
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:332
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:528
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