EMCY.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 "EMCY.h"
26 #include "ds301.h"
27 
28 #include "Logging.h"
29 #include "exceptions.h"
30 
31 namespace icl_hardware {
32 namespace canopen_schunk {
33 
34 // static initializers of error_maps
35 std::map <uint16_t, std::string> EMCY::m_eec_map;
36 std::map <uint8_t, std::string> EMCY::m_error_register_map;
37 
38 EMCY::EMCY(const uint8_t node_id)
39  : m_node_id(node_id)
40 {
41 }
42 
43 void EMCY::update(const CanMsg& msg)
44 {
45  uint8_t node_id = msg.id - ds301::ID_EMCY_MIN + 1;
46 
47  if (node_id != m_node_id)
48  {
49  LOGGING_ERROR_C(CanOpen, EMCY, "EMCY Update called with wrong canopen ID. Received ID: "
50  << node_id << " Node ID: " << m_node_id
51  << ". Update ignored." << endl);
52  return;
53  }
54 
55 
56  if (msg.dlc != 8)
57  {
58  std::stringstream ss;
59  ss << "Unexpected length " << static_cast<int>(msg.dlc) << " of EMCY message. Expected 8.";
60  LOGGING_ERROR_C (CanOpen, SDO, ss.str() << endl);
61  return;
62  }
63 
64  boost::mutex::scoped_lock(m_data_buffer_mutex);
65  // isolate information from message
66  m_eec = msg.data[0] + (msg.data[1] << 8);
67  m_error_register = msg.data[2];
68  m_msef.resize(5);
69  for (size_t i = 3; i < 8; ++i)
70  {
71  m_msef[i-3] = msg.data[i];
72  }
73 
75  {
77  LOGGING_INFO_C(CanOpen, EMCY, "Error reset EMCY received. Node " << m_node_id
78  << " is now in state error free." << endl);
79  }
80  else
81  {
83  std::stringstream ss;
84  ss << "EMCY message states that an error in node "
85  << static_cast<int>(m_node_id) << " occured: "
86  << lookupEECString(m_eec) << std::endl
87  << "Error registers: " << lookupErrorRegisterString(m_error_register) << std::endl
88  << "Manufacturer specific code: " << lookupMSEFString();
89  LOGGING_ERROR_C(CanOpen, EMCY, ss.str() << endl);
90  }
91 }
92 
94 {
95  boost::mutex::scoped_lock(m_data_buffer_mutex);
96  return m_error_state;
97 }
98 
99 bool EMCY::getErrorInformation(uint16_t& eec, uint8_t& error_register, std::vector< uint8_t >& msef)
100 {
101  boost::mutex::scoped_lock(m_data_buffer_mutex);
102 
103  // No error occured, so we can give no valid error information
105  {
106  return false;
107  }
108 
109  eec = m_eec;
110  error_register = m_error_register;
111  msef = m_msef;
112  return true;
113 }
114 
115 std::string EMCY::lookupEECString(const uint16_t error_code)
116 {
117  std::stringstream ss;
118  ss << std::endl;
119  uint16_t nibble_validator = 0xF000;
120  uint16_t subcode = error_code & nibble_validator;
121  std::map<uint16_t, std::string>::iterator map_it = m_eec_map.find(subcode);
122  if (map_it != m_eec_map.end())
123  {
124  ss << map_it->second << std::endl;
125  uint16_t nibble_validator_next = nibble_validator >> 4;
126  uint16_t next_nibble = error_code & nibble_validator_next;
127  ++map_it;
128 
129  // DS402 allows additional functions to be defined directly as 0xF00N
130  // (according to table 3 in CiA DSP-402 V1.1)
131  while (next_nibble == 0 && nibble_validator_next > 0)
132  {
133  subcode |= next_nibble;
134  nibble_validator += nibble_validator_next;
135  nibble_validator_next = nibble_validator_next >> 4;
136  next_nibble = error_code & nibble_validator_next;
137  }
138 
139  // Iterate forward in the map (it is sorted) as long as the code matches
140  while ((map_it->first & nibble_validator) == subcode)
141  {
142  if ( (map_it->first & nibble_validator_next) == next_nibble )
143  {
144  // found the next nibble. Move everything forward one nibble.
145  while ((map_it->first & nibble_validator_next) != 0 && subcode != error_code)
146  {
147  subcode |= next_nibble;
148  nibble_validator += nibble_validator_next;
149  nibble_validator_next = nibble_validator_next >> 4;
150  next_nibble = error_code & nibble_validator_next;
151  }
152 
153  if ( (map_it->first - subcode) == 0 )
154  {
155  // add value to output string
156  ss << map_it->second << std::endl;
157  }
158  }
159  ++map_it;
160  }
161 
162  // If the error code was more specific than the most specific entry found, we inform the user about that.
163  if (subcode != error_code)
164  {
165  ss << "Error code could not be fully parsed. Full error code was " << hexToString(error_code) << std::endl;
166  }
167 
168  return ss.str();
169  }
170  else
171  {
172  std::stringstream ss;
173  ss << "Unknown emergency error code: " << hexToString(error_code);
174  return ss.str();
175  }
176 }
177 
178 std::string EMCY::lookupErrorRegisterString ( const uint8_t error_code )
179 {
180  std::stringstream ss;
181 
182  if (m_error_register_map.size() == 0)
183  {
184  ss << "No error register description set. Returning plain register code: "
185  << hexToString(error_code) << std::endl;
186  }
187  else
188  {
189  for (size_t i = 0; i < (sizeof(error_code) * 8); ++i)
190  {
191  uint8_t bit = (0x01 << i) & error_code;
192  std::map<uint8_t, std::string>::iterator map_it = m_error_register_map.find(bit);
193  if (map_it != m_error_register_map.end())
194  {
195  ss << map_it->second << ", ";
196  }
197  }
198  }
199 
200  if (ss.str().empty())
201  {
202  ss << "Unknown error register code: " << hexToString(error_code);
203  }
204  return ss.str();
205 }
206 
207 
208 std::string EMCY::lookupMSEFString() const
209 {
210  return hexArrayToString(&m_msef[0], m_msef.size());
211 }
212 
213 void EMCY::addEmergencyErrorMap(const std::string& filename, const std::string& block_identifier)
214 {
215  std::map<uint32_t, std::string> new_entries = getErrorMapFromConfigFile(filename, block_identifier);
216  for (std::map<uint32_t, std::string>::iterator it = new_entries.begin();
217  it != new_entries.end();
218  ++it)
219  {
220  uint16_t index = static_cast<uint16_t>(it->first);
221  m_eec_map[index] = it->second;
222  }
223 }
224 
225 void EMCY::addErrorRegisterMap ( const std::string& filename, const std::string& block_identifier )
226 {
227  std::map<uint32_t, std::string> new_entries = getErrorMapFromConfigFile(filename, block_identifier);
228  for (std::map<uint32_t, std::string>::iterator it = new_entries.begin();
229  it != new_entries.end();
230  ++it)
231  {
232  uint8_t index = static_cast<uint8_t>(it->first);
233  m_error_register_map[index] = it->second;
234  }
235 }
236 
237 void EMCY::printError (SDO& sdo, const uint8_t error_nr)
238 {
239  std::vector<uint8_t> uploaded_data;
240  sdo.upload(false, 0x1003, error_nr, uploaded_data);
241 
242  if (uploaded_data.size() != 4) // should be uint32
243  {
244  throw ProtocolException (0x1003, error_nr, "Uploaded data size does not match 4");
245  }
246 
247  uint16_t eec = uploaded_data[0] + (uploaded_data[1] << 8);
248  uint16_t additional_information = uploaded_data[2] + (uploaded_data[3] << 8);
249 
250  std::stringstream ss;
251  ss << " Error " << static_cast<int>(error_nr) << ": "
252  << lookupEECString(eec) << std::endl
253  << "Additional information: " << hexToString(additional_information);
254  LOGGING_ERROR_C(CanOpen, EMCY, ss.str() << endl);
255 }
256 
257 
259 {
260  // first get the number of recorded errors
261  uint8_t num_errors;
262  sdo.upload(false, 0x1003, 0, num_errors);
263 
264  LOGGING_INFO_C (CanOpen, EMCY, num_errors << " errors in error history:" << endl);
265 
266  // get all present errors
267  for (size_t i = 1; i <= num_errors; ++i)
268  {
269  printError (sdo, i);
270  }
271 
272 }
273 
275 {
276  // write 0 to 0x1003/0
277  uint8_t value = 0;
278  sdo.download(false, 0x1003, 0, value);
279 }
280 
281 
282 
283 
284 }}//end of NS
static std::string lookupEECString(const uint16_t error_code)
Definition: EMCY.cpp:115
#define LOGGING_INFO_C(streamname, classname, arg)
void printLastErrors(SDO &sdo)
Print all errors present in error register 0x1003.
Definition: EMCY.cpp:258
static void addEmergencyErrorMap(const std::string &filename, const std::string &block_identifier)
Adds new information from an ini file to the emergency error map.
Definition: EMCY.cpp:213
void clearErrorHistory(SDO &sdo)
Clear the error register 0x1003.
Definition: EMCY.cpp:274
virtual void update(const CanMsg &msg)
update Updates the EMCY object with a received EMCY Message
Definition: EMCY.cpp:43
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
uint16_t m_eec
emergency_error_code;
Definition: EMCY.h:151
Basic CanOpen exception that contains the Object dictionary index and subindex.
Definition: exceptions.h:37
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
eEMCY_STATUS getEmcyStatus() const
Returns the state of the EMCY state machine.
Definition: EMCY.cpp:93
static std::map< uint16_t, std::string > m_eec_map
Definition: EMCY.h:157
static const uint16_t ID_EMCY_MIN
Definition: ds301.h:47
unsigned char uint8_t
bool getErrorInformation(uint16_t &eec, uint8_t &error_register, std::vector< uint8_t > &msef)
Returns the full error information.
Definition: EMCY.cpp:99
ThreadStream & endl(ThreadStream &stream)
The EMCY class handles the spontaneously occurring Emergency (EMCY) messages, keeps track of a nodes ...
Definition: EMCY.h:42
void printError(SDO &sdo, const uint8_t error_nr=1)
Prints a specific error from the error register 0x1003.
Definition: EMCY.cpp:237
EMCY(const uint8_t node_id)
EMCY Constructs a new EMCY object. The error map will be filled separately.
Definition: EMCY.cpp:38
static const uint16_t EMCY_ERROR_RESET_NO_ERROR
Definition: EMCY.h:58
static std::string lookupErrorRegisterString(const uint8_t error_code)
Definition: EMCY.cpp:178
static std::map< uint8_t, std::string > m_error_register_map
Definition: EMCY.h:158
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
eEMCY_STATUS
DS301 requests state error_free and error_occurred. This could be mapped into a bool, but maybe some other implementation needs more states, so we use an enum.
Definition: EMCY.h:52
The SDO class represents Service Data Objects (SDO) that are used for slow access of the canOpen obje...
Definition: SDO.h:40
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
uint8_t m_error_register
register in which the error occured
Definition: EMCY.h:148
std::string hexToString(const uint64_t num)
Converts a hexadecimal number into its string representation 0xXX.
Definition: helper.cpp:33
boost::mutex m_data_buffer_mutex
Definition: EMCY.h:155
std::vector< uint8_t > m_msef
manufacturer-specific error code
Definition: EMCY.h:145
static void addErrorRegisterMap(const std::string &filename, const std::string &block_identifier)
Adds new information from an ini file to the error_register map.
Definition: EMCY.cpp:225
unsigned short uint16_t
#define LOGGING_ERROR_C(streamname, classname, arg)
virtual std::string lookupMSEFString() const
Definition: EMCY.cpp:208


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