00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00023
00024
00025 #include "SDO.h"
00026 #include "ds301.h"
00027
00028 #include "Logging.h"
00029
00030 #include <boost/thread/mutex.hpp>
00031
00032 namespace icl_hardware {
00033 namespace canopen_schunk {
00034
00035
00036 std::map <uint32_t, std::string> SDO::m_error_map;
00037
00038 SDO::SDO(const uint8_t& node_id,const CanDevPtr& can_device)
00039 : m_node_id(node_id),
00040 m_can_device(can_device),
00041 m_response_wait_time_ms(100),
00042 m_data_update_received(false)
00043 {
00044 }
00045
00046 void SDO::update(const CanMsg& msg)
00047 {
00048 uint8_t node_id = msg.id - ds301::ID_TSDO_MIN + 1;
00049
00050 if (node_id != m_node_id)
00051 {
00052 std::stringstream ss;
00053 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.";
00054 LOGGING_ERROR_C(CanOpen,SDO, ss.str() << endl);
00055 return;
00056 }
00057
00058 boost::mutex::scoped_lock(m_data_buffer_mutex);
00059
00060 if (msg.dlc != 8)
00061 {
00062 std::stringstream ss;
00063 ss << "Unexpected length " << static_cast<int>(msg.dlc) << " of SDO response. Expected 8.";
00064 throw ResponseException(0,0,ss.str());
00065 }
00066
00067 if (m_data_update_received)
00068 {
00069 std::stringstream ss;
00070 ss << "Data buffer contains unprocessed data which will be overwritten.";
00071 LOGGING_WARNING_C (CanOpen, SDO, ss.str() << endl);
00072 }
00073
00074 m_data_buffer.clear();
00075 for (size_t i = 0; i < msg.dlc; ++i)
00076 {
00077 m_data_buffer.push_back(msg.data[i]);
00078 }
00079
00080 m_data_update_received = true;
00081 m_data_buffer_updated_cond.notify_one();
00082 }
00083
00084 bool SDO::download(const bool normal_transfer,
00085 const uint16_t index,
00086 const uint8_t subindex,
00087 const std::vector< uint8_t >& usrdata)
00088 {
00089
00090 size_t num_bytes = usrdata.size();
00091 if (num_bytes > 4 || normal_transfer)
00092 {
00093 std::string mode = "expedited";
00094 if (normal_transfer)
00095 {
00096 mode = "segmented";
00097 }
00098 std::stringstream ss;
00099 ss << "So far only expedited transfers with maximum 4 data bytes are supported. "
00100 << "However, " << mode << " transfer of " << num_bytes
00101 << " bytes was requested. Aborting download";
00102 throw ProtocolException (index, subindex, ss.str());
00103 }
00104
00105 if (num_bytes == 0)
00106 {
00107 throw ProtocolException (index, subindex, "Empty data message passed to download function.");
00108 }
00109
00110 CanMsg msg;
00111
00112 msg.id = ds301::ID_RSDO_MIN + m_node_id - 1;
00113 msg.dlc = 8;
00114 msg.rtr = 0;
00115 switch (num_bytes)
00116 {
00117 case 1:
00118 msg.data[0] = SDO_SEG_REQ_INIT_DOWNLOAD_1BYTE;
00119 break;
00120 case 2:
00121 msg.data[0] = SDO_SEG_REQ_INIT_DOWNLOAD_2BYTE;
00122 break;
00123 case 3:
00124 msg.data[0] = SDO_SEG_REQ_INIT_DOWNLOAD_3BYTE;
00125 break;
00126 case 4:
00127 msg.data[0] = SDO_SEG_REQ_INIT_DOWNLOAD_4BYTE;
00128 break;
00129 default:
00130 msg.data[0] = SDO_SEG_REQ_INIT_DOWNLOAD_xBYTE;
00131 break;
00132 }
00133
00134 msg.data[1] = index & 0xff;
00135 msg.data[2] = index >> 8;
00136 msg.data[3] = subindex;
00137 for (size_t i = 0; i < 4; ++i)
00138 {
00139 if (i < num_bytes)
00140 {
00141 msg.data[4 + i] = usrdata[i];
00142 }
00143 else
00144 {
00145 msg.data[4 + i] = 0;
00146 }
00147 }
00148
00149
00150 m_can_device->Send(msg);
00151
00152
00153 boost::mutex::scoped_lock buffer_guard(m_data_buffer_mutex);
00154
00155 if (!m_data_update_received)
00156 {
00157
00158 if (!m_data_buffer_updated_cond.timed_wait(buffer_guard,
00159 boost::posix_time::milliseconds(m_response_wait_time_ms)))
00160 {
00161 throw (TimeoutException(index, subindex, "No response to SDO download request received!"));
00162 }
00163 }
00164
00165
00166
00167
00168
00169 m_data_update_received = false;
00170
00171
00172
00173 if ( m_data_buffer.size() != 8 )
00174 {
00175 std::stringstream ss;
00176 ss << "Unexpected length " << m_data_buffer.size() << " of SDO response. Expected 8.";
00177 throw (ProtocolException(index, subindex, ss.str()));
00178 }
00179 if ( m_data_buffer[0] == SDO_SEG_ABORT_TRANSFER )
00180 {
00181 uint32_t error_code = m_data_buffer[4] + (m_data_buffer[5]<<8) + (m_data_buffer[6]<<16) + (m_data_buffer[7]<<24);
00182 std::stringstream ss;
00183 ss << "SDO transfer aborted: " << lookupErrorString(error_code);
00184 throw ProtocolException(index, subindex, ss.str());
00185 }
00186 else if ( m_data_buffer[0] != SDO_SEG_RES_INIT_DOWNLOAD )
00187 {
00188 std::stringstream ss;
00189 ss << "Invalid SDO response, got " << hexToString(m_data_buffer[0])
00190 << " expected " << hexToString(SDO_SEG_RES_INIT_DOWNLOAD);
00191 throw ResponseException(index, subindex, ss.str());
00192 }
00193
00194 uint32_t rdindex = m_data_buffer[1] + (m_data_buffer[2]<<8);
00195 uint8_t rdsubindex = m_data_buffer[3];
00196 if (rdindex != index || rdsubindex != subindex)
00197 {
00198 std::stringstream ss;
00199 ss << "Invalid index/subindex, expected " << hexToString(index) << "/" << hexToString(subindex)
00200 << ", got " << hexToString(rdindex) << "/" << hexToString(rdsubindex);
00201 throw ResponseException(index, subindex, ss.str());
00202 }
00203
00204
00205 return true;
00206 }
00207
00208
00209 bool SDO::upload(const bool normal_transfer,
00210 const uint16_t index,
00211 const uint8_t subindex,
00212 std::vector<uint8_t>& uploaded_data)
00213 {
00214
00215 if (normal_transfer)
00216 {
00217 LOGGING_ERROR_C(CanOpen, SDO, "So far only expedited transfers with maximum 4 data bytes "
00218 << "are supported. "
00219 << "However, blocked transfer of was requested. Aborting upload" << endl);
00220 return false;
00221 }
00222
00223 CanMsg msg;
00224
00225 msg.id = ds301::ID_RSDO_MIN + m_node_id - 1;
00226 msg.dlc = 8;
00227 msg.rtr = 0;
00228 msg.data[0] = SDO_SEG_REQ_INIT_UPLOAD;
00229 msg.data[1] = index & 0xff;
00230 msg.data[2] = index >> 8;
00231 msg.data[3] = subindex;
00232
00233
00234 m_can_device->Send(msg);
00235
00236
00237 boost::mutex::scoped_lock buffer_guard(m_data_buffer_mutex);
00238
00239 if (!m_data_update_received)
00240 {
00241
00242 if (!m_data_buffer_updated_cond.timed_wait(buffer_guard,
00243 boost::posix_time::milliseconds(m_response_wait_time_ms)))
00244 {
00245 throw (TimeoutException(index, subindex, "No response to SDO upload request received!"));
00246 }
00247 }
00248
00249
00250
00251
00252
00253 m_data_update_received = false;
00254
00255
00256 if ( m_data_buffer.size() != 8 )
00257 {
00258 std::stringstream ss;
00259 ss << "Unexpected length " << m_data_buffer.size() << " of SDO response. Expected 8.";
00260 throw ProtocolException (index, subindex, ss.str());
00261 }
00262 if ( m_data_buffer[0] == SDO_SEG_ABORT_TRANSFER )
00263 {
00264 uint32_t error_code = m_data_buffer[4] + (m_data_buffer[5]<<8) + (m_data_buffer[6]<<16) + (m_data_buffer[7]<<24);
00265 std::stringstream ss;
00266 ss << "SDO transfer aborted: " << lookupErrorString(error_code);
00267 throw ProtocolException(index, subindex, ss.str());
00268 }
00269
00270 uint32_t rdindex = m_data_buffer[1] + (m_data_buffer[2]<<8);
00271 uint8_t rdsubindex = m_data_buffer[3];
00272 if (rdindex != index || rdsubindex != subindex)
00273 {
00274 std::stringstream ss;
00275 ss << "Invalid index/subindex, expected " << hexToString(index) << "/" << hexToString(subindex)
00276 << ", got " << hexToString(rdindex) << "/" << hexToString(rdsubindex);
00277 throw ResponseException (index, subindex, ss.str());
00278 }
00279
00280 uploaded_data.clear();
00281 uint8_t num_bytes = 0;
00282
00283 switch (m_data_buffer[0])
00284 {
00285 case SDO_SEG_RES_INIT_UPLOAD_1BYTE:
00286 {
00287 num_bytes = 1;
00288 break;
00289 }
00290 case SDO_SEG_RES_INIT_UPLOAD_2BYTE:
00291 {
00292 num_bytes = 2;
00293 break;
00294 }
00295 case SDO_SEG_RES_INIT_UPLOAD_3BYTE:
00296 {
00297 num_bytes = 3;
00298 break;
00299 }
00300 case SDO_SEG_RES_INIT_UPLOAD_4BYTE:
00301 {
00302 num_bytes = 4;
00303 break;
00304 }
00305 default:
00306 {
00307 std::stringstream ss;
00308 ss << "Illegal SDO upload response received. Please note that so far only expedited "
00309 << " uploads with a data length of up to 4 bytes are supported.\n"
00310 << "Received response was " << hexArrayToString(&m_data_buffer[0], m_data_buffer.size());
00311 throw ResponseException (index, subindex, ss.str());
00312 }
00313 }
00314
00315 for (size_t i = 0; i < num_bytes; ++i)
00316 {
00317 uploaded_data.push_back(m_data_buffer[4+i]);
00318 }
00319
00320 return true;
00321 }
00322
00323 std::string SDO::lookupErrorString(const uint32_t error_code)
00324 {
00325 std::map<uint32_t, std::string>::iterator map_it = m_error_map.find(error_code);
00326 if (map_it != m_error_map.end())
00327 {
00328 return map_it->second;
00329 }
00330 else
00331 {
00332 std::stringstream ss;
00333 ss << "Unknown error code: " << hexToString(error_code);
00334 return ss.str();
00335 }
00336 }
00337
00338
00339 void SDO::addErrorMapFromFile(const std::string& filename)
00340 {
00341 std::map<uint32_t, std::string> new_entries = getErrorMapFromConfigFile(filename);
00342 m_error_map.insert(new_entries.begin(), new_entries.end());
00343
00344 LOGGING_DEBUG(CanOpen, "Added error codes from " << filename << endl);
00345 }
00346
00347
00348 }}