Lely core libraries 2.3.4
driver.cpp
Go to the documentation of this file.
1
24#include "coapp.hpp"
25
26#if !LELY_NO_COAPP_MASTER
27
28#include <lely/coapp/driver.hpp>
29
30#include <algorithm>
31#include <array>
32#include <string>
33
34#include <cassert>
35
36namespace lely {
37
38namespace canopen {
39
41 : master(master_),
42 rpdo_mapped(master.RpdoMapped(id)),
43 tpdo_mapped(master.TpdoMapped(id)),
44 tpdo_event_mutex(master.tpdo_event_mutex),
45 exec_(exec ? exec : static_cast<ev_exec_t*>(master.GetExecutor())),
46 id_(id) {
47 master.Insert(*this);
48}
49
50BasicDriver::~BasicDriver() { master.Erase(*this); }
51
52void
54 if (driver.Number() < 1 || driver.Number() > 8)
55 throw ::std::out_of_range("invalid logical device number: " +
56 ::std::to_string(driver.Number()));
57 if (find(driver.id()) != end())
58 throw ::std::out_of_range("logical device number " +
59 ::std::to_string(driver.Number()) +
60 " already registered");
61
62 MapType::operator[](driver.Number()) = &driver;
63}
64
65void
67 auto it = find(driver.Number());
68 if (it != end() && it->second == &driver) erase(it);
69}
70
73 if (num) {
74 auto it = find(num);
75 if (it != end()) return it->second->AsyncConfig();
76 } else if (size() == 1) {
77 // Shortcut in case of a single logical device.
78 return begin()->second->AsyncConfig();
79 } else if (!empty()) {
80 ::std::array<SdoFuture<void>, 8> futures;
81 ::std::size_t n = 0;
82 // Post an OnConfig() task for each logical device driver.
83 for (const auto& it : *this) futures[n++] = it.second->AsyncConfig();
84 // Create a temporary array of pointers, since SdoFuture is not guaranteed
85 // to be the same size as ev_future_t*.
86 ::std::array<ev_future_t*, 8> tmp;
87 ::std::copy(futures.begin(), futures.end(), tmp.begin());
88 // Create a future which becomes ready when all OnConfig() tasks have
89 // finished.
90 return ev::when_all(GetExecutor(), n, tmp.data())
91 // Check the results of the tasks.
93 for (const auto& it : futures) {
94 // Throw an exception in an error occurred.
95 if (it) it.get().value();
96 }
97 });
98 }
99 return make_empty_sdo_future();
100}
101
104 if (num) {
105 auto it = find(num);
106 if (it != end()) return it->second->AsyncDeconfig();
107 } else if (size() == 1) {
108 // Shortcut in case of a single logical device.
109 return begin()->second->AsyncDeconfig();
110 } else if (!empty()) {
111 ::std::array<SdoFuture<void>, 8> futures;
112 ::std::size_t n = 0;
113 // Post an OnConfig() task for each logical device driver.
114 for (const auto& it : *this) futures[n++] = it.second->AsyncDeconfig();
115 assert(n <= 8);
116 // Create a temporary array of pointers, since SdoFuture is not guaranteed
117 // to be the same size as ev_future_t*.
118 ::std::array<ev_future_t*, 8> tmp;
119 ::std::copy(futures.begin(), futures.end(), tmp.begin());
120 // Create a future which becomes ready when all OnDeconfig() tasks have
121 // finished.
122 return ev::when_all(GetExecutor(), n, tmp.data())
123 // Check the results of the tasks.
124 .then(GetExecutor(), [futures](ev::Future<::std::size_t, void>) {
125 for (const auto& it : futures) {
126 // Throw an exception in an error occurred.
127 if (it) it.get().value();
128 }
129 });
130 }
131 return make_empty_sdo_future();
132}
133
134void
136 io::CanState old_state) noexcept {
137 for (const auto& it : *this) it.second->OnCanState(new_state, old_state);
138}
139
140void
142 for (const auto& it : *this) it.second->OnCanError(error);
143}
144
145void
146BasicDriver::OnRpdoWrite(uint16_t idx, uint8_t subidx) noexcept {
147 if (idx >= 0x6000 && idx <= 0x9fff) {
148 int num = (idx - 0x6000) / 0x800 + 1;
149 auto it = find(num);
150 if (it != end()) it->second->OnRpdoWrite(idx - (num - 1) * 0x800, subidx);
151 } else {
152 for (const auto& it : *this) it.second->OnRpdoWrite(idx, subidx);
153 }
154}
155
156void
158 for (const auto& it : *this) it.second->OnCommand(cs);
159}
160
161void
162BasicDriver::OnHeartbeat(bool occurred) noexcept {
163 for (const auto& it : *this) it.second->OnHeartbeat(occurred);
164}
165
166void
168 for (const auto& it : *this) it.second->OnState(st);
169}
170
171void
172BasicDriver::OnSync(uint8_t cnt, const time_point& t) noexcept {
173 for (const auto& it : *this) it.second->OnSync(cnt, t);
174}
175
176void
177BasicDriver::OnSyncError(uint16_t eec, uint8_t er) noexcept {
178 for (const auto& it : *this) it.second->OnSyncError(eec, er);
179}
180
181void
183 const ::std::chrono::system_clock::time_point& abs_time) noexcept {
184 for (const auto& it : *this) it.second->OnTime(abs_time);
185}
186
187void
188BasicDriver::OnEmcy(uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept {
189 for (const auto& it : *this) it.second->OnEmcy(eec, er, msef);
190}
191
192void
193BasicDriver::OnNodeGuarding(bool occurred) noexcept {
194 for (const auto& it : *this) it.second->OnNodeGuarding(occurred);
195}
196
197void
198BasicDriver::OnBoot(NmtState st, char es, const ::std::string& what) noexcept {
199 for (const auto& it : *this) it.second->OnBoot(st, es, what);
200}
201
202void
204 ::std::function<void(::std::error_code ec)> res) noexcept {
205 if (empty()) {
206 // Shortcut if no logical device drivers have been registered.
207 res(::std::error_code{});
208 } else {
209 try {
210 auto f = AsyncConfig();
211 // Invoke res() when AsyncConfig() completes.
212 f.submit(GetExecutor(), [res, f] {
213 // Extract the error code from the exception pointer, if any.
214 ::std::error_code ec;
215 auto& result = f.get();
216 if (result.has_error()) {
217 try {
218 ::std::rethrow_exception(result.error());
219 } catch (const ::std::system_error& e) {
220 ec = e.code();
221 } catch (...) {
222 // Ignore exceptions we cannot handle.
223 }
224 }
225 res(ec);
226 });
227 } catch (::std::system_error& e) {
228 res(e.code());
229 }
230 }
231}
232
233void
234BasicDriver::OnDeconfig(
235 ::std::function<void(::std::error_code ec)> res) noexcept {
236 if (empty()) {
237 // Shortcut if no logical device drivers have been registered.
238 res(::std::error_code{});
239 } else {
240 try {
241 auto f = AsyncDeconfig();
242 // Invoke res() when AsyncConfig() completes.
243 f.submit(GetExecutor(), [res, f] {
244 // Extract the error code from the exception pointer, if any.
245 ::std::error_code ec;
246 auto& result = f.get();
247 if (result.has_error()) {
248 try {
249 ::std::rethrow_exception(result.error());
250 } catch (const ::std::system_error& e) {
251 ec = e.code();
252 } catch (...) {
253 // Ignore exceptions we cannot handle.
254 }
255 }
256 res(ec);
257 });
258 } catch (::std::system_error& e) {
259 res(e.code());
260 }
261 }
262}
263
264} // namespace canopen
265
266} // namespace lely
267
268#endif // !LELY_NO_COAPP_MASTER
void OnCommand(NmtCommand cs) noexcept override
The default implementation notifies all registered logical device drivers.
Definition: driver.cpp:157
void OnSyncError(uint16_t eec, uint8_t er) noexcept override
The default implementation notifies all registered logical device drivers.
Definition: driver.cpp:177
void OnCanState(io::CanState new_state, io::CanState old_state) noexcept override
The default implementation notifies all registered logical device drivers.
Definition: driver.cpp:135
SdoFuture< void > AsyncDeconfig(int num=0)
Invokes LogicalDriverBase::AsyncDeconfig() for the specified logical device driver.
Definition: driver.cpp:103
void OnEmcy(uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept override
The default implementation notifies all registered logical device drivers.
Definition: driver.cpp:188
void Insert(LogicalDriverBase &driver)
Registers a logical device driver for the remote node.
Definition: driver.cpp:53
SdoFuture< void > AsyncConfig(int num=0)
Invokes LogicalDriverBase::AsyncConfig() for the specified logical device driver.
Definition: driver.cpp:72
void OnState(NmtState st) noexcept override
The default implementation notifies all registered logical device drivers.
Definition: driver.cpp:167
void Erase(LogicalDriverBase &driver)
Unregisters a logical device driver for the remote node.
Definition: driver.cpp:66
void OnSync(uint8_t cnt, const time_point &t) noexcept override
The default implementation notifies all registered logical device drivers.
Definition: driver.cpp:172
ev::Executor GetExecutor() const noexcept final
Returns the executor used to execute event handlers for this driver, including SDO confirmation funct...
Definition: driver.hpp:311
void OnHeartbeat(bool occurred) noexcept override
The default implementation notifies all registered logical device drivers.
Definition: driver.cpp:162
void OnNodeGuarding(bool occurred) noexcept override
The default implementation notifies all registered logical device drivers.
Definition: driver.cpp:193
BasicDriver(ev_exec_t *exec, BasicMaster &master, uint8_t id)
Creates a new driver for a remote CANopen node and registers it with the master.
Definition: driver.cpp:40
void OnConfig(::std::function< void(::std::error_code ec)> res) noexcept override
The default implementation invokes AsyncConfig() to start the configuration process for all registere...
Definition: driver.cpp:203
void OnRpdoWrite(uint16_t idx, uint8_t subidx) noexcept override
The default implementation notifies all registered logical device drivers, unless the object index is...
Definition: driver.cpp:146
void OnBoot(NmtState st, char es, const ::std::string &what) noexcept override
The default implementation notifies all registered logical device drivers.
Definition: driver.cpp:198
void OnTime(const ::std::chrono::system_clock::time_point &abs_time) noexcept override
The default implementation notifies all registered logical device drivers.
Definition: driver.cpp:182
void OnCanError(io::CanError error) noexcept override
The default implementation notifies all registered logical device drivers.
Definition: driver.cpp:141
BasicMaster & master
A reference to the master with which this driver is registered.
Definition: driver.hpp:1097
The CANopen master.
Definition: master.hpp:50
void Erase(DriverBase &driver)
Unregisters a driver for a remote CANopen node.
Definition: master.cpp:274
void Insert(DriverBase &driver)
Registers a driver for a remote CANopen node.
Definition: master.cpp:257
virtual uint8_t id() const noexcept=0
Returns the node-ID.
The abstract driver interface for a logical device on a remote CANopen node.
Definition: driver.hpp:258
virtual int Number() const noexcept=0
Returns the number of the logical device on the remote node.
The type of objects thrown as exceptions to report a system error with an associated error code.
Definition: exception.hpp:54
A future.
Definition: future.hpp:384
This is the internal header file of the C++ CANopen application library.
This header file is part of the C++ CANopen application library; it contains the remote node driver i...
CanError
The error flags of a CAN bus, which are not mutually exclusive.
Definition: err.hpp:47
CanState
The states of a CAN node, depending on the TX/RX error count.
Definition: err.hpp:33
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
SdoFuture< void > make_empty_sdo_future()
Returns an SDO future with a shared state that is immediately ready, containing a successful result o...
Definition: sdo.hpp:73
NmtState
The NMT states.
Definition: node.hpp:56
NmtCommand
The NMT command specifiers.
Definition: node.hpp:42