SDO.cpp
Go to the documentation of this file.
1 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
2 
3 // -- BEGIN LICENSE BLOCK ----------------------------------------------
4 // This file is part of the SCHUNK Canopen Driver suite.
5 //
6 // This program is free software licensed under the LGPL
7 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
8 // You can find a copy of this license in LICENSE folder in the top
9 // directory of the source code.
10 //
11 // © Copyright 2016 SCHUNK GmbH, Lauffen/Neckar Germany
12 // © Copyright 2016 FZI Forschungszentrum Informatik, Karlsruhe, Germany
13 // -- END LICENSE BLOCK ------------------------------------------------
14 
15 //----------------------------------------------------------------------
23 //----------------------------------------------------------------------
24 
25 #include "SDO.h"
26 #include "ds301.h"
27 
28 #include "Logging.h"
29 
30 #include <boost/thread/mutex.hpp>
31 
32 namespace icl_hardware {
33 namespace canopen_schunk {
34 
35 // static initializer of error_map
36 std::map <uint32_t, std::string> SDO::m_error_map;
37 
38 SDO::SDO(const uint8_t& node_id,const CanDevPtr& can_device)
39  : m_node_id(node_id),
40  m_can_device(can_device),
41  m_response_wait_time_ms(100),
42  m_data_update_received(false)
43 {
44 }
45 
46 void SDO::update(const CanMsg& msg)
47 {
48  uint8_t node_id = msg.id - ds301::ID_TSDO_MIN + 1;
49 
50  if (node_id != m_node_id)
51  {
52  std::stringstream ss;
53  ss << "SDO Update called with wrong canopen ID. Received ID: " << static_cast<int>(node_id) << " Node ID: " << static_cast<int>(m_node_id) << ". Update ignored.";
54  LOGGING_ERROR_C(CanOpen,SDO, ss.str() << endl);
55  return;
56  }
57 
58  boost::mutex::scoped_lock(m_data_buffer_mutex);
59 
60  if (msg.dlc != 8)
61  {
62  std::stringstream ss;
63  ss << "Unexpected length " << static_cast<int>(msg.dlc) << " of SDO response. Expected 8.";
64  throw ResponseException(0,0,ss.str());
65  }
66 
68  {
69  std::stringstream ss;
70  ss << "Data buffer contains unprocessed data which will be overwritten.";
71  LOGGING_WARNING_C (CanOpen, SDO, ss.str() << endl);
72  }
73 
74  m_data_buffer.clear();
75  for (size_t i = 0; i < msg.dlc; ++i)
76  {
77  m_data_buffer.push_back(msg.data[i]);
78  }
79 
82 }
83 
84 bool SDO::download(const bool normal_transfer,
85  const uint16_t index,
86  const uint8_t subindex,
87  const std::vector< uint8_t >& usrdata)
88 {
89  //TODO: support normal transfer as well
90  size_t num_bytes = usrdata.size();
91  if (num_bytes > 4 || normal_transfer)
92  {
93  std::string mode = "expedited";
94  if (normal_transfer)
95  {
96  mode = "segmented";
97  }
98  std::stringstream ss;
99  ss << "So far only expedited transfers with maximum 4 data bytes are supported. "
100  << "However, " << mode << " transfer of " << num_bytes
101  << " bytes was requested. Aborting download";
102  throw ProtocolException (index, subindex, ss.str());
103  }
104 
105  if (num_bytes == 0)
106  {
107  throw ProtocolException (index, subindex, "Empty data message passed to download function.");
108  }
109 
110  CanMsg msg;
111 
112  msg.id = ds301::ID_RSDO_MIN + m_node_id - 1;
113  msg.dlc = 8;
114  msg.rtr = 0;
115  switch (num_bytes)
116  {
117  case 1:
119  break;
120  case 2:
122  break;
123  case 3:
125  break;
126  case 4:
128  break;
129  default:
131  break;
132  }
133 
134  msg.data[1] = index & 0xff;
135  msg.data[2] = index >> 8;
136  msg.data[3] = subindex;
137  for (size_t i = 0; i < 4; ++i)
138  {
139  if (i < num_bytes)
140  {
141  msg.data[4 + i] = usrdata[i];
142  }
143  else
144  {
145  msg.data[4 + i] = 0;
146  }
147  }
148 
149  // Send download request over CAN bus
150  m_can_device->Send(msg);
151 
152  // Lock the data buffer access
153  boost::mutex::scoped_lock buffer_guard(m_data_buffer_mutex);
154 
156  {
157  // Wait some time for the resonse...
158  if (!m_data_buffer_updated_cond.timed_wait(buffer_guard,
159  boost::posix_time::milliseconds(m_response_wait_time_ms)))
160  {
161  throw (TimeoutException(index, subindex, "No response to SDO download request received!"));
162  }
163  }
164 
165  /* New data will be processed next. As we might return from the function at many points,
166  * we enable data receiving here again, as it will be locked by the mutex
167  * until the end of this function, anyway.
168  */
169  m_data_update_received = false;
170 
171 
172  // sanitizing again
173  if ( m_data_buffer.size() != 8 )
174  {
175  std::stringstream ss;
176  ss << "Unexpected length " << m_data_buffer.size() << " of SDO response. Expected 8.";
177  throw (ProtocolException(index, subindex, ss.str()));
178  }
180  {
181  uint32_t error_code = m_data_buffer[4] + (m_data_buffer[5]<<8) + (m_data_buffer[6]<<16) + (m_data_buffer[7]<<24);
182  std::stringstream ss;
183  ss << "SDO transfer aborted: " << lookupErrorString(error_code);
184  throw ProtocolException(index, subindex, ss.str());
185  }
186  else if ( m_data_buffer[0] != SDO_SEG_RES_INIT_DOWNLOAD )
187  {
188  std::stringstream ss;
189  ss << "Invalid SDO response, got " << hexToString(m_data_buffer[0])
190  << " expected " << hexToString(SDO_SEG_RES_INIT_DOWNLOAD);
191  throw ResponseException(index, subindex, ss.str());
192  }
193 
194  uint32_t rdindex = m_data_buffer[1] + (m_data_buffer[2]<<8);
195  uint8_t rdsubindex = m_data_buffer[3];
196  if (rdindex != index || rdsubindex != subindex)
197  {
198  std::stringstream ss;
199  ss << "Invalid index/subindex, expected " << hexToString(index) << "/" << hexToString(subindex)
200  << ", got " << hexToString(rdindex) << "/" << hexToString(rdsubindex);
201  throw ResponseException(index, subindex, ss.str());
202  }
203 
204  // If we reached this point, everything is fine :)
205  return true;
206 }
207 
208 
209 bool SDO::upload(const bool normal_transfer,
210  const uint16_t index,
211  const uint8_t subindex,
212  std::vector<uint8_t>& uploaded_data)
213 {
214  //TODO: support normal transfer as well
215  if (normal_transfer)
216  {
217  LOGGING_ERROR_C(CanOpen, SDO, "So far only expedited transfers with maximum 4 data bytes "
218  << "are supported. "
219  << "However, blocked transfer of was requested. Aborting upload" << endl);
220  return false;
221  }
222 
223  CanMsg msg;
224 
225  msg.id = ds301::ID_RSDO_MIN + m_node_id - 1;
226  msg.dlc = 8;
227  msg.rtr = 0;
228  msg.data[0] = SDO_SEG_REQ_INIT_UPLOAD;
229  msg.data[1] = index & 0xff;
230  msg.data[2] = index >> 8;
231  msg.data[3] = subindex;
232 
233  // Send upload request over CAN bus
234  m_can_device->Send(msg);
235 
236  // Lock the data buffer access
237  boost::mutex::scoped_lock buffer_guard(m_data_buffer_mutex);
238 
240  {
241  // Wait some time for the response...
242  if (!m_data_buffer_updated_cond.timed_wait(buffer_guard,
243  boost::posix_time::milliseconds(m_response_wait_time_ms)))
244  {
245  throw (TimeoutException(index, subindex, "No response to SDO upload request received!"));
246  }
247  }
248 
249  /* New data will be processed next. As we might return from the function at many points,
250  * we enable data receiving here again, as it will be locked by the mutex
251  * until the end of this function, anyway.
252  */
253  m_data_update_received = false;
254 
255  // sanitizing again
256  if ( m_data_buffer.size() != 8 )
257  {
258  std::stringstream ss;
259  ss << "Unexpected length " << m_data_buffer.size() << " of SDO response. Expected 8.";
260  throw ProtocolException (index, subindex, ss.str());
261  }
263  {
264  uint32_t error_code = m_data_buffer[4] + (m_data_buffer[5]<<8) + (m_data_buffer[6]<<16) + (m_data_buffer[7]<<24);
265  std::stringstream ss;
266  ss << "SDO transfer aborted: " << lookupErrorString(error_code);
267  throw ProtocolException(index, subindex, ss.str());
268  }
269 
270  uint32_t rdindex = m_data_buffer[1] + (m_data_buffer[2]<<8);
271  uint8_t rdsubindex = m_data_buffer[3];
272  if (rdindex != index || rdsubindex != subindex)
273  {
274  std::stringstream ss;
275  ss << "Invalid index/subindex, expected " << hexToString(index) << "/" << hexToString(subindex)
276  << ", got " << hexToString(rdindex) << "/" << hexToString(rdsubindex);
277  throw ResponseException (index, subindex, ss.str());
278  }
279 
280  uploaded_data.clear();
281  uint8_t num_bytes = 0;
282 
283  switch (m_data_buffer[0])
284  {
286  {
287  num_bytes = 1;
288  break;
289  }
291  {
292  num_bytes = 2;
293  break;
294  }
296  {
297  num_bytes = 3;
298  break;
299  }
301  {
302  num_bytes = 4;
303  break;
304  }
305  default:
306  {
307  std::stringstream ss;
308  ss << "Illegal SDO upload response received. Please note that so far only expedited "
309  << " uploads with a data length of up to 4 bytes are supported.\n"
310  << "Received response was " << hexArrayToString(&m_data_buffer[0], m_data_buffer.size());
311  throw ResponseException (index, subindex, ss.str());
312  }
313  }
314 
315  for (size_t i = 0; i < num_bytes; ++i)
316  {
317  uploaded_data.push_back(m_data_buffer[4+i]);
318  }
319 
320  return true;
321 }
322 
323 std::string SDO::lookupErrorString(const uint32_t error_code)
324 {
325  std::map<uint32_t, std::string>::iterator map_it = m_error_map.find(error_code);
326  if (map_it != m_error_map.end())
327  {
328  return map_it->second;
329  }
330  else
331  {
332  std::stringstream ss;
333  ss << "Unknown error code: " << hexToString(error_code);
334  return ss.str();
335  }
336 }
337 
338 
339 void SDO::addErrorMapFromFile(const std::string& filename)
340 {
341  std::map<uint32_t, std::string> new_entries = getErrorMapFromConfigFile(filename);
342  m_error_map.insert(new_entries.begin(), new_entries.end());
343 
344  LOGGING_DEBUG(CanOpen, "Added error codes from " << filename << endl);
345 }
346 
347 
348 }}// end of NS
unsigned int uint32_t
static unsigned char const SDO_SEG_REQ_INIT_DOWNLOAD_3BYTE
Definition: SDO.h:61
static unsigned char const SDO_SEG_REQ_INIT_DOWNLOAD_1BYTE
Definition: SDO.h:59
static unsigned char const SDO_SEG_RES_INIT_UPLOAD_2BYTE
Definition: SDO.h:69
static const uint16_t ID_RSDO_MIN
Definition: ds301.h:78
SDO(const uint8_t &node_id, const CanDevPtr &can_device)
Definition: SDO.cpp:38
static unsigned char const SDO_SEG_REQ_INIT_UPLOAD
Definition: SDO.h:65
std::string hexArrayToString(const unsigned char *msg, const uint8_t length)
Transforms an array of unsigned chars into a string of Hex representations of those chars...
Definition: helper.cpp:42
Basic CanOpen exception that contains the Object dictionary index and subindex.
Definition: exceptions.h:37
#define LOGGING_DEBUG(streamname, arg)
bool download(const bool normal_transfer, const uint16_t index, const uint8_t subindex, const std::vector< uint8_t > &usrdata)
Downloads SDO data from the master to the slave (From PC to node).
Definition: SDO.cpp:84
If a device response times out, this exception will be thrown.
Definition: exceptions.h:91
static unsigned char const SDO_SEG_RES_INIT_UPLOAD_4BYTE
Definition: SDO.h:71
#define LOGGING_WARNING_C(streamname, classname, arg)
static std::string lookupErrorString(const uint32_t error_code)
Definition: SDO.cpp:323
unsigned char uint8_t
Exceptions relating to device responses.
Definition: exceptions.h:68
ThreadStream & endl(ThreadStream &stream)
boost::mutex m_data_buffer_mutex
Definition: SDO.h:215
void update(const CanMsg &msg)
update updates the SDO data with newly received messages
Definition: SDO.cpp:46
std::vector< uint8_t > m_data_buffer
Definition: SDO.h:217
static unsigned char const SDO_SEG_REQ_INIT_DOWNLOAD_2BYTE
Definition: SDO.h:60
boost::condition_variable m_data_buffer_updated_cond
Definition: SDO.h:216
bool upload(const bool normal_transfer, const uint16_t index, const uint8_t subindex, std::vector< uint8_t > &uploaded_data)
Uploads data from a slave (node) to a master (PC).
Definition: SDO.cpp:209
The SDO class represents Service Data Objects (SDO) that are used for slow access of the canOpen obje...
Definition: SDO.h:40
static void addErrorMapFromFile(const std::string &filename)
Adds an error map from an INI file to all SDOs. This should be called once to get human readable erro...
Definition: SDO.cpp:339
std::map< uint32_t, std::string > getErrorMapFromConfigFile(const std::string &filename, const std::string &category)
Creates an error map from a given INI file.
Definition: helper.cpp:75
static std::map< uint32_t, std::string > m_error_map
Definition: SDO.h:219
static unsigned char const SDO_SEG_ABORT_TRANSFER
Definition: SDO.h:75
static const uint16_t ID_TSDO_MIN
Definition: ds301.h:76
static unsigned char const SDO_SEG_RES_INIT_UPLOAD_3BYTE
Definition: SDO.h:70
std::string hexToString(const uint64_t num)
Converts a hexadecimal number into its string representation 0xXX.
Definition: helper.cpp:33
static unsigned char const SDO_SEG_REQ_INIT_DOWNLOAD_4BYTE
Definition: SDO.h:62
void notify_one() BOOST_NOEXCEPT
unsigned short uint16_t
static unsigned char const SDO_SEG_RES_INIT_DOWNLOAD
Definition: SDO.h:63
#define LOGGING_ERROR_C(streamname, classname, arg)
static unsigned char const SDO_SEG_REQ_INIT_DOWNLOAD_xBYTE
Definition: SDO.h:58
static unsigned char const SDO_SEG_RES_INIT_UPLOAD_1BYTE
Definition: SDO.h:68


schunk_canopen_driver
Author(s): Felix Mauch , Georg Heppner
autogenerated on Mon Jun 10 2019 15:07:49