MIRA
CANOpenSDOClient.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 MetraLabs GmbH (MLAB), GERMANY.
3  * All rights reserved.
4  * Contact: info@MetraLabs.com
5  *
6  * Commercial Usage:
7  * Licensees holding valid commercial licenses may use this file in
8  * accordance with the commercial license agreement provided with the
9  * software or, alternatively, in accordance with the terms contained in
10  * a written agreement between you and MetraLabs.
11  *
12  * GNU General Public License Usage:
13  * Alternatively, this file may be used under the terms of the GNU
14  * General Public License version 3.0 as published by the Free Software
15  * Foundation and appearing in the file LICENSE.GPL3 included in the
16  * packaging of this file. Please review the following information to
17  * ensure the GNU General Public License version 3.0 requirements will be
18  * met: http://www.gnu.org/copyleft/gpl.html.
19  * Alternatively you may (at your option) use any later version of the GNU
20  * General Public License if such license has been publicly approved by
21  * MetraLabs (or its successors, if any).
22  *
23  * IN NO EVENT SHALL "MLAB" BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
24  * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE
25  * OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF "MLABS" HAS BEEN
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * "MLAB" SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
29  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
31  * "AS IS" BASIS, AND "MLAB" HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
32  * SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS.
33  */
34 
43 #ifndef _MLAB_CANOPENSDOCLIENT_H_
44 #define _MLAB_CANOPENSDOCLIENT_H_
45 
46 #include <map>
47 
48 #ifndef Q_MOC_RUN
49 #include <boost/thread/future.hpp>
50 #include <boost/thread/mutex.hpp>
51 
52 #include <boost/format.hpp>
53 #endif
54 
55 #include <error/Exceptions.h>
56 #include <utils/UUID.h>
57 
58 #include <can/CANInterface.h>
59 #include <can/CANOpenDefs.h>
60 #include <can/CANOpenUtil.h>
61 #include <can/SDOFuture.h>
62 
63 namespace mira { namespace can {
64 
66 
74 {
75 public:
78 
84 
86  virtual ~CANOpenSDOClient();
87 
89 
90 public:
93 
101  template<typename T>
102  SDOFuture<T> read(uint8 node, uint16 index, uint8 subIndex)
103  {
104  boost::shared_ptr<ReadRequest<T>> request(new ReadRequest<T>(node, index, subIndex));
105  boost::mutex::scoped_lock lock(mReadRequestsMutex);
106  uint64 requestID = getNextRequestID();
107  mReadRequests[requestID] = request;
108  sendSDOReadRequest(request);
109  return SDOFuture<T>(request->promise.get_future(), this, requestID);
110  }
111 
121  template<typename T>
122  T readSync(uint8 node, uint16 index, uint8 subIndex,
123  Duration waitTime = Duration::milliseconds(50),
124  uint32 maxTries=5)
125  {
126  uint32 tries = 0;
127  while(tries++ < maxTries)
128  {
129  auto r = read<T>(node, index, subIndex);
130  if (r.timedWait(waitTime))
131  return r.get();
132  }
133  MIRA_THROW(XTimeout, "Timeout during read SDO " << std::hex
134  << "node(0x" << boost::format("%02x") % (int)node << ") "
135  << "index(0x" << boost::format("%04x") % index << ") "
136  << "subindex (0x" << boost::format("%02x") % (int)subIndex << ")");
137  return T();
138  }
139 
145  CANOpenNodeInfo readNodeInfo(uint8 node);
146 
148 
149 public:
152 
161  template<typename T>
162  SDOFuture<void> write(uint8 node, uint16 index, uint8 subIndex, T value)
163  {
164  CANMessage message;
165  std::size_t size = CANOpenUtil::write<T>(message, 4, value);
166 
167  boost::shared_ptr<WriteRequest> request(new WriteRequest(node, index, subIndex));
168  boost::mutex::scoped_lock lock(mWriteRequestsMutex);
169  uint64 requestID = getNextRequestID();
170  mWriteRequests[requestID] = request;
171  sendSDOWriteRequest(request, message, size);
172  return SDOFuture<void>(request->promise.get_future(), this, requestID);
173  }
174 
185  template<typename T>
186  SDOFuture<void> writeSync(uint8 node, uint16 index, uint8 subIndex, T value,
187  Duration waitTime = Duration::milliseconds(50),
188  uint32 maxTries=5)
189  {
190  uint32 tries = 0;
191  while(tries++ < maxTries)
192  {
193  auto w = write<T>(node, index, subIndex, value);
194  if (w.timedWait(waitTime))
195  return w;
196  }
197  MIRA_THROW(XTimeout, "Timeout during write SDO " << std::hex
198  << "node(0x" << boost::format("%02x") % (int)node << ") "
199  << "index(0x" << boost::format("%04x") % index << ") "
200  << "subindex (0x" << boost::format("%02x") % (int)subIndex << ")");
201  }
202 
204 
205 public:
206  virtual void onDestructFuture(uint64 requestID);
207 
208 private:
210  // Internal base class of SDO uploads (read)
211 
212  class ReadWriteRequestBase
213  {
214  public:
215  ReadWriteRequestBase(uint8 iNode, uint16 iIdx, uint8 iSubIdx) :
216  node(iNode), idx(iIdx), subIdx(iSubIdx) {}
217  virtual ~ReadWriteRequestBase() {}
218  public:
219  virtual void setMessage(const CANMessage& message, std::size_t offset) = 0;
220  virtual void setException(const Exception& ex) = 0;
221  public:
222  uint8 node;
223  uint16 idx;
224  uint8 subIdx;
225  };
226 
228  // Internal template class for handling SDO uploads (read)
229 
230  template<typename T>
231  class ReadRequest :
232  public ReadWriteRequestBase
233  {
234  public:
235  ReadRequest(uint8 iNode, uint16 iIdx, uint8 iSubIdx) :
236  ReadWriteRequestBase(iNode, iIdx, iSubIdx) {}
237  virtual ~ReadRequest() {}
238  public:
239  virtual void setMessage(const CANMessage& message, std::size_t offset) {
240  T value = CANOpenUtil::read<T>(message, offset);
241  promise.set_value(value);
242  }
243  virtual void setException(const Exception& ex) {
244  promise.set_exception(boost::copy_exception(ex));
245  }
246  public:
247  boost::promise<T> promise;
248  };
249 
251  // Internal class for handling SDO downloads (write)
252 
253  class WriteRequest : public ReadWriteRequestBase
254  {
255  public:
256  WriteRequest(uint8 iNode, uint16 iIdx, uint8 iSubIdx) :
257  ReadWriteRequestBase(iNode, iIdx, iSubIdx) {}
258  virtual ~WriteRequest() {}
259  public:
260  virtual void setMessage(const CANMessage& message, std::size_t offset) {
261  promise.set_value();
262  }
263  virtual void setException(const Exception& ex) {
264  promise.set_exception(boost::copy_exception(ex));
265  }
266  public:
267  boost::promise<void> promise;
268  };
269 
270  typedef boost::shared_ptr<ReadWriteRequestBase> RequestPtr;
271  typedef std::map<uint64, RequestPtr> RequestList;
272 
274 
275 private:
277  void sendSDOReadRequest(RequestPtr iRequest);
278 
280  void sendSDOWriteRequest(RequestPtr iRequest,
281  CANMessage& iMessage, std::size_t iSize);
282 
284  void processSDOMessage(const CANMessage& iMsg, const Time& time);
285 
287  static uint64 getNextRequestID() {
288  static uint64 sNextRequestID = 0;
289  static boost::mutex sIDMutex;
290 
291  boost::mutex::scoped_lock lock(sIDMutex);
292  return(sNextRequestID++);
293  }
294 
295 private:
296  CANInterfacePtr mCAN;
297  uint32 mCallbackID;
298 
299  RequestList mReadRequests;
300  boost::mutex mReadRequestsMutex;
301  RequestList mWriteRequests;
302  boost::mutex mWriteRequestsMutex;
303 };
304 
306 typedef boost::shared_ptr<CANOpenSDOClient> CANOpenSDOClientPtr;
307 
309 
310 }} // namespaces
311 
312 #endif
TEigenFormat< Derived > format(Eigen::MatrixBase< Derived > &matrix, Eigen::IOFormat format=EigenFormat::matlab())
tick_type milliseconds() const
T readSync(uint8 node, uint16 index, uint8 subIndex, Duration waitTime=Duration::milliseconds(50), uint32 maxTries=5)
Perform a synchronous SDO upload (read operation)
Definition: CANOpenSDOClient.h:122
Abstract class for a hardware specific CAN driver.
boost::shared_ptr< CANInterface > CANInterfacePtr
A shared pointer of the CANInterface.
Definition: CANInterface.h:224
Global definitions of the CANopen standard.
A CANopen SDO client.
Definition: CANOpenSDOClient.h:73
#define MIRA_THROW(ex, msg)
Definition: SDOFuture.h:54
boost::shared_ptr< CANOpenSDOClient > CANOpenSDOClientPtr
A shared pointer of the CANOpenSDOClient.
Definition: CANOpenSDOClient.h:306
This is a specialization for SDO calls with the return type of void, where no get() method is availab...
Definition: SDOFuture.h:221
#define MLAB_CAN_EXPORT
Definition: CANExports.h:57
A SDOFuture is a proxy for the result of an asynchronous SDO upload or download.
Definition: SDOFuture.h:163
Implementation of a future for SDO read and write operations.
A struct, which contains standard information about a CANopen node.
Definition: CANOpenDefs.h:165
CANopen utility functions.
SDOFuture< void > write(uint8 node, uint16 index, uint8 subIndex, T value)
Perform an expedited SDO download (a write operation)
Definition: CANOpenSDOClient.h:162
A definition of a CAN message.
Definition: CANDefs.h:105
SDOFuture< void > writeSync(uint8 node, uint16 index, uint8 subIndex, T value, Duration waitTime=Duration::milliseconds(50), uint32 maxTries=5)
Perform a synchronous write operation.
Definition: CANOpenSDOClient.h:186
SDOFuture< T > read(uint8 node, uint16 index, uint8 subIndex)
Perform an expedited SDO upload (a read operation)
Definition: CANOpenSDOClient.h:102