test_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 //----------------------------------------------------------------------
22 //----------------------------------------------------------------------
23 
25 
29 
32 
33 #include <boost/test/unit_test.hpp>
34 #include <boost/thread/thread.hpp>
35 using namespace icl_hardware::canopen_schunk;
36 
37 
38 BOOST_AUTO_TEST_SUITE(ts_sdo)
39 
40 BOOST_AUTO_TEST_CASE (sdo_download)
41 {
42  // Initializing
45  LOGGING_INFO(CanOpen, "-----------------------------------" << endl <<
46  "-----Running SDO download test-----" << endl <<
47  "-----------------------------------" << endl);
48 
49  CanOpenController my_controller("Dummy");
51  can_device = boost::dynamic_pointer_cast<icl_hardware::can::tCanDeviceDummy>(my_controller.getCanDevice());
52 
53  // Add one node
54  my_controller.addGroup<DS301Group>("testgroup");
55  my_controller.addNode<DS301Node>(1, "testgroup");
56  DS301Group::Ptr my_group = my_controller.getGroup<DS301Group>("testgroup");
57  DS301Node::Ptr node = my_group->getNodes().front();
58 
59 
60  // Create some data that should be downloaded to the slave node
61  std::vector<uint8_t> data(4);
62  data[0] = 0x00;
63  data[1] = 0x01;
64  data[2] = 0x02;
65  data[3] = 0x03;
66  uint32_t index = 300;
67  uint8_t subindex = 3;
68 
69  // create node response
70  CanMsg response;
71  response.id = ds301::ID_TSDO_MIN; // SDO for first node
72  response.dlc = 8;
73  response.rtr = 0;
75  response.data[1] = index & 0xff;
76  response.data[2] = index >> 8;
77  response.data[3] = subindex & 0xff;
78  can_device->addResponse(response);
79 
80  // If download succeeds and the response is correct, this will pass
81  BOOST_REQUIRE(node->m_sdo.download(false, index, subindex, data));
82 
83  // parse the sent can message that was created by the download request
84  CanMsg msg = can_device->getLastMessage();
85  LOGGING_INFO(CanOpen, hexArrayToString(msg.data, msg.dlc) << endl);
86  BOOST_REQUIRE(msg.dlc == 8);
87  BOOST_REQUIRE(msg.rtr == 0);
88  BOOST_REQUIRE(msg.data[0] == SDO::SDO_SEG_REQ_INIT_DOWNLOAD_4BYTE);
89  BOOST_REQUIRE(msg.data[1] == (index & 0xff));
90  BOOST_REQUIRE(msg.data[2] == (index >> 8));
91  BOOST_REQUIRE(msg.data[3] == subindex);
92  BOOST_REQUIRE(msg.data[4] == data[0]);
93  BOOST_REQUIRE(msg.data[5] == data[1]);
94  BOOST_REQUIRE(msg.data[6] == data[2]);
95  BOOST_REQUIRE(msg.data[7] == data[3]);
96  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
97  std::cout << "\n";
98 
99  // Now let's generate some faulty responses. They should all fail.
100  response.dlc = 13; // some arbitrary illegal number
101  can_device->addResponse(response);
102 
103  BOOST_REQUIRE_THROW(node->m_sdo.download(false, index, subindex, data), std::exception);
104  response.dlc = 8;
105  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
106  std::cout << "\n";
107 
108 
109  // This will produce a timeout as the message will never reach the SDO
110  response.id = ds301::ID_TSDO_MIN-1;
111  can_device->addResponse(response);
112  BOOST_REQUIRE_THROW(node->m_sdo.download(false, index, subindex, data), TimeoutException);
113  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
114  std::cout << "\n";
115 
116  // This will also produce a timout, as the node to this sdo does not exist
117  response.id = ds301::ID_TSDO_MIN+1;
118  can_device->addResponse(response);
119  BOOST_REQUIRE_THROW(node->m_sdo.download(false, index, subindex, data), TimeoutException);
120  response.id = ds301::ID_TSDO_MIN;
121  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
122  std::cout << "\n";
123 
124  // This will produce a wrong response error
125  response.data[0] = SDO::SDO_SEG_RES_INIT_DOWNLOAD | 0x01;
126  can_device->addResponse(response);
127  BOOST_REQUIRE_THROW(node->m_sdo.download(false, index, subindex, data), ResponseException);
128  response.data[0] = SDO::SDO_SEG_RES_INIT_DOWNLOAD;
129  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
130  std::cout << "\n";
131 
132  // LSB byte of index is wrong
133  response.data[1] = (index+1) & 0xff;
134  can_device->addResponse(response);
135  BOOST_REQUIRE_THROW(node->m_sdo.download(false, index, subindex, data), ResponseException);
136  response.data[1] = index & 0xff;
137  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
138  std::cout << "\n";
139 
140  // MSB byte of index is wrong
141  response.data[2] = (index+256) >> 8;
142  can_device->addResponse(response);
143  BOOST_REQUIRE_THROW(node->m_sdo.download(false, index, subindex, data), ResponseException);
144  response.data[2] = index >> 8;
145  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
146  std::cout << "\n";
147 
148  // Subindex is wrong
149  response.data[3] = (subindex+1) & 0xff;
150  can_device->addResponse(response);
151  BOOST_REQUIRE_THROW(node->m_sdo.download(false, index, subindex, data), ResponseException);
152  response.data[3] = subindex & 0xff;
153  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
154  std::cout << "\n";
155 
156  // blocked downloads are not yet supported
157  can_device->addResponse(response);
158  try {
159  BOOST_REQUIRE(!(node->m_sdo.download(true, index, subindex, data)));
160  }
161  catch (const std::exception& e)
162  {
163  LOGGING_ERROR_C (CanOpen, SDO, e.what() << endl);
164  }
165  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
166  std::cout << "\n";
167 
168  // illegal number of sent bytes
169  can_device->addResponse(response);
170  std::vector<uint8_t> empty_data;
171  BOOST_REQUIRE_THROW (node->m_sdo.download(false, index, subindex, empty_data), ProtocolException);
172  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
173  std::cout << "\n";
174 
175  // illegal number of sent bytes
176  can_device->addResponse(response);
177  empty_data.resize(5);
178  try {
179  BOOST_REQUIRE(!(node->m_sdo.download(false, index, subindex, empty_data)));
180  }
181  catch (const std::exception& e)
182  {
183  LOGGING_ERROR_C (CanOpen, SDO, e.what() << endl);
184  }
185  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
186  std::cout << "\n";
187 }
188 
189 
190 BOOST_AUTO_TEST_CASE (sdo_download_test_interfaces)
191 {
192  // Initializing
195  LOGGING_INFO(CanOpen, "---------------------------------------------" << endl <<
196  "-----Running SDO download interface test-----" << endl <<
197  "---------------------------------------------" << endl);
198 
199  CanOpenController my_controller("Dummy");
201  can_device = boost::dynamic_pointer_cast<icl_hardware::can::tCanDeviceDummy>(my_controller.getCanDevice());
202 
203  // Add one node
204  my_controller.addGroup<DS301Group>("testgroup");
205  my_controller.addNode<DS301Node>(1, "testgroup");
206  DS301Group::Ptr my_group = my_controller.getGroup<DS301Group>("testgroup");
207  DS301Node::Ptr node = my_group->getNodes().front();
208 
209 
210  // Create some data that should be downloaded to the slave node
211  std::vector<uint8_t> data(4);
212  data[0] = 0x00;
213  data[1] = 0x01;
214  data[2] = 0x02;
215  data[3] = 0x03;
216  uint32_t index = 300;
217  uint8_t subindex = 3;
218 
219  // create node response
220  CanMsg response;
221  response.id = ds301::ID_TSDO_MIN; // SDO for first node
222  response.dlc = 8;
223  response.rtr = 0;
224  response.data[0] = SDO::SDO_SEG_RES_INIT_DOWNLOAD;
225  response.data[1] = index & 0xff;
226  response.data[2] = index >> 8;
227  response.data[3] = subindex & 0xff;
228  can_device->addResponse(response);
229 
230  BOOST_REQUIRE_NO_THROW(node->m_sdo.download(false, index, subindex, data));
231  // parse the sent can message that was created by the download request
232  CanMsg msg1 = can_device->getLastMessage();
233 
234  can_device->addResponse(response);
235  uint32_t data_block = (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
236  LOGGING_INFO (CanOpen, hexToString(data_block) << endl);
237  BOOST_REQUIRE_NO_THROW(node->m_sdo.download(false, index, subindex, data_block));
238 
239  // parse the sent can message that was created by the download request
240  CanMsg msg2 = can_device->getLastMessage();
241  LOGGING_INFO(CanOpen, hexArrayToString(msg2.data, msg2.dlc) << endl);
242 
243  BOOST_REQUIRE(msg2.dlc == 8);
244  BOOST_REQUIRE(msg2.rtr == 0);
245  BOOST_REQUIRE(msg2.data[1] == (index & 0xff));
246  BOOST_REQUIRE(msg2.data[0] == SDO::SDO_SEG_REQ_INIT_DOWNLOAD_4BYTE);
247  BOOST_REQUIRE(msg2.data[2] == (index >> 8));
248  BOOST_REQUIRE(msg2.data[3] == subindex);
249  BOOST_REQUIRE(msg2.data[4] == data[0]);
250  BOOST_REQUIRE(msg2.data[5] == data[1]);
251  BOOST_REQUIRE(msg2.data[6] == data[2]);
252  BOOST_REQUIRE(msg2.data[7] == data[3]);
253 
254  BOOST_REQUIRE(msg1.data[4] == msg2.data[4]);
255  BOOST_REQUIRE(msg1.data[5] == msg2.data[5]);
256  BOOST_REQUIRE(msg1.data[6] == msg2.data[6]);
257  BOOST_REQUIRE(msg1.data[7] == msg2.data[7]);
258 }
259 
261 {
262  // Initializing
265  LOGGING_INFO(CanOpen, "---------------------------------" << endl <<
266  "-----Running SDO upload test-----" << endl <<
267  "---------------------------------" << endl);
268 
269  CanOpenController my_controller("Dummy");
271  can_device = boost::dynamic_pointer_cast<icl_hardware::can::tCanDeviceDummy>(my_controller.getCanDevice());
272 
273  // Add one node
274  my_controller.addGroup<DS301Group>("testgroup");
275  my_controller.addNode<DS301Node>(1, "testgroup");
276  DS301Group::Ptr my_group = my_controller.getGroup<DS301Group>("testgroup");
277  DS301Node::Ptr node = my_group->getNodes().front();
278 
279 
280  uint32_t index = 300;
281  uint8_t subindex = 3;
282 
283  // This is the data that will be uploaded from the slave to the master.
284  std::vector<uint8_t> data(4);
285  data[0] = 0x01;
286  data[1] = 0x02;
287  data[2] = 0x03;
288  data[3] = 0x04;
289 
290  // create node response
291  CanMsg response;
292  response.id = ds301::ID_TSDO_MIN; // SDO for first node
293  response.dlc = 8;
294  response.rtr = 0;
296  response.data[1] = index & 0xff;
297  response.data[2] = index >> 8;
298  response.data[3] = subindex & 0xff;
299  response.data[4] = data[0];
300  response.data[5] = data[1];
301  response.data[6] = data[2];
302  response.data[7] = data[3];
303  can_device->addResponse(response);
304 
305  std::vector<uint8_t> uploaded_data;
306 
307  // If upload succeeds and the response is valid, this will pass
308  try
309  {
310  BOOST_REQUIRE(node->m_sdo.upload(false, index, subindex, uploaded_data));
311  }
312  catch (const std::exception& e)
313  {
314  LOGGING_ERROR (CanOpen, e.what() << endl);
315  }
316 
317  // did the node upload the correct data?
318  BOOST_REQUIRE(data == uploaded_data);
319 
320  // parse the sent can message that was created by the upload request
321  CanMsg msg = can_device->getLastMessage();
322  LOGGING_INFO(CanOpen, hexArrayToString(msg.data, msg.dlc) << endl);
323  BOOST_REQUIRE(msg.dlc == 8);
324  BOOST_REQUIRE(msg.rtr == 0);
325  BOOST_REQUIRE(msg.data[0] == SDO::SDO_SEG_REQ_INIT_UPLOAD);
326  BOOST_REQUIRE(msg.data[1] == (index & 0xff));
327  BOOST_REQUIRE(msg.data[2] == (index >> 8));
328  BOOST_REQUIRE(msg.data[3] == subindex);
329 
330  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
331  std::cout << "\n";
332 
333  // Now let's generate some faulty responses. They should all fail.
334  response.dlc = 13; // some arbitrary illegal number
335  can_device->addResponse(response);
336  BOOST_REQUIRE_THROW (node->m_sdo.download(false, index, subindex, uploaded_data), TimeoutException);
337  response.dlc = 8;
338  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
339  std::cout << "\n";
340 
341 
342  // This will produce a timeout as the message will never reach the SDO
343  response.id = ds301::ID_TSDO_MIN-1;
344  can_device->addResponse(response);
345  BOOST_REQUIRE_THROW (node->m_sdo.download(false, index, subindex, uploaded_data), TimeoutException);
346  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
347  std::cout << "\n";
348 
349  // This will also produce a timout, as the node to this sdo does not exist
350  response.id = ds301::ID_TSDO_MIN+1;
351  can_device->addResponse(response);
352  BOOST_REQUIRE_THROW (node->m_sdo.download(false, index, subindex, uploaded_data), TimeoutException);
353  response.id = ds301::ID_TSDO_MIN;
354  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
355  std::cout << "\n";
356 
357  // This will produce a wrong response error
358  response.data[0] = SDO::SDO_SEG_REQ_INIT_UPLOAD | 0x04;
359  can_device->addResponse(response);
360  BOOST_REQUIRE_THROW (node->m_sdo.download(false, index, subindex, uploaded_data), ResponseException);
361  response.data[0] = SDO::SDO_SEG_REQ_INIT_UPLOAD;
362  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
363  std::cout << "\n";
364 
365  // LSB byte of index is wrong
366  response.data[1] = (index+1) & 0xff;
367  can_device->addResponse(response);
368  BOOST_REQUIRE_THROW (node->m_sdo.download(false, index, subindex, uploaded_data), ResponseException);
369  response.data[1] = index & 0xff;
370  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
371  std::cout << "\n";
372 
373  // MSB byte of index is wrong
374  response.data[2] = (index+256) >> 8;
375  can_device->addResponse(response);
376  BOOST_REQUIRE_THROW (node->m_sdo.download(false, index, subindex, uploaded_data), ResponseException);
377  response.data[2] = index >> 8;
378  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
379  std::cout << "\n";
380 
381  // Subindex is wrong
382  response.data[3] = (subindex+1) & 0xff;
383  can_device->addResponse(response);
384  BOOST_REQUIRE_THROW (node->m_sdo.download(false, index, subindex, uploaded_data), ResponseException);
385  response.data[3] = subindex & 0xff;
386  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
387  std::cout << "\n";
388 
389  // blocked uploads are not yet supported
390  can_device->addResponse(response);
391  BOOST_REQUIRE(!(node->m_sdo.upload(true, index, subindex, uploaded_data)));
392 
393  boost::this_thread::sleep(boost::posix_time::milliseconds(200));
394  std::cout << "\n";
395 
396 
397  // send a response with an error
398  response.data[0] = 0x80; // abort transfer
399  std::vector<uint8_t> char_vec = convertToCharVector(0x06010000); // Unsupported access to an object
400  response.data[4] = char_vec[0];
401  response.data[5] = char_vec[1];
402  response.data[6] = char_vec[2];
403  response.data[7] = char_vec[3];
404  can_device->addResponse(response);
405  BOOST_REQUIRE_THROW (node->m_sdo.download(false, index, subindex, uploaded_data), ProtocolException);
406  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
407  std::cout << "\n";
408 }
409 
410 BOOST_AUTO_TEST_SUITE_END()
unsigned int uint32_t
bool initialize(int &argc, char *argv[], bool remove_read_arguments)
static unsigned char const SDO_SEG_REQ_INIT_UPLOAD
Definition: SDO.h:65
CanDevPtr getCanDevice() const
Get a handle to the current CAN device. This is basically for debugging with a Dummy Can Device...
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
#define LOGGING_INFO(streamname, arg)
Basic CanOpen exception that contains the Object dictionary index and subindex.
Definition: exceptions.h:37
std::vector< uint8_t > convertToCharVector(const T value)
This little helper transforms any datatype that has a size of at most 4 Bytes into a vector of uint8_...
Definition: helper.h:104
If a device response times out, this exception will be thrown.
Definition: exceptions.h:91
The DS301Group class is the base Class for all canOpen device groups, providing basic interfaces to t...
Definition: DS301Group.h:41
static unsigned char const SDO_SEG_RES_INIT_UPLOAD_4BYTE
Definition: SDO.h:71
#define LOGGING_ERROR(streamname, arg)
The CanOpenController class is the main entry point for any calls to the canOpen System.
unsigned char uint8_t
Exceptions relating to device responses.
Definition: exceptions.h:68
ThreadStream & endl(ThreadStream &stream)
void setLogLevel(icl_core::logging::LogLevel log_level)
The SDO class represents Service Data Objects (SDO) that are used for slow access of the canOpen obje...
Definition: SDO.h:40
boost::shared_ptr< GroupT > getGroup(const std::string &index="default")
Returns a shared pointer to the group with a given index if possible.
BOOST_AUTO_TEST_CASE(sdo_download)
Definition: test_sdo.cpp:40
void addNode(const uint8_t node_id, const std::string &group_name="default")
Adds a new node to a group. If the group is not found (e.g. it was not created before), nothing will be done.
static const uint16_t ID_TSDO_MIN
Definition: ds301.h:76
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 addGroup(const std::string &identifier)
Adds a new node group with a given identifier. The group&#39;s type is given as template parameter...
static unsigned char const SDO_SEG_RES_INIT_DOWNLOAD
Definition: SDO.h:63
#define LOGGING_ERROR_C(streamname, classname, arg)
The DS301Node class Is the base class representation of canOpen devices. It is the access point to th...
Definition: DS301Node.h:67


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