35 #include "sdo_error.h"
36 #include "global_config.h"
47 m_send_and_wait_receivers.fill(received_unassigned_sdo);
50 void SDO::download(uint8_t node_id, uint16_t index, uint8_t subindex, uint32_t size,
const std::vector<uint8_t>& data) {
53 assert(data.size()>=size);
59 uint8_t command = Flag::initiate_download_request
61 | Flag::size_indicated
62 | Flag::expedited_transfer;
66 (size>1) ? data[1] : (uint8_t) 0,
67 (size>2) ? data[2] : (uint8_t) 0,
68 (size>3) ? data[3] : (uint8_t) 0
78 throw sdo_error(sdo_error::type::segmented_download);
84 std::vector<uint8_t>
SDO::upload(uint8_t node_id, uint16_t index, uint8_t subindex) {
86 std::vector<uint8_t> result;
88 uint8_t command = Flag::initiate_upload_request;
95 if (response.
command & Flag::expedited_transfer) {
97 for (
unsigned i=0; i<response.
get_length(); ++i) {
98 result.push_back(response.
data[3+i]);
103 if ((response.
command & Flag::size_indicated)==0) {
104 throw sdo_error(sdo_error::type::response_command,
"Command "+std::to_string(response.
command)+
" is reserved for further use.");
108 uint32_t original_size = response.
get_data() & 0xFFFF;
109 uint32_t size = original_size;
110 bool more_segments =
true;
111 uint8_t toggle_bit = 0;
114 while (more_segments) {
117 WARN(
"[SDO::upload] [Restrictive] Uploaded already all "<<original_size<<
" bytes but there are still more segments. Ignore...");
121 uint8_t command = Flag::upload_segment_request
129 if (toggle_bit != (response.
command & Flag::toggle_bit)) {
130 throw sdo_error(sdo_error::type::response_toggle_bit);
134 while(i<7 && size>0) {
135 result.push_back(response.
data[i]);
140 toggle_bit = (toggle_bit>0) ? 0 : Flag::toggle_bit;
141 more_segments = (response.
command & Flag::no_more_segments)==0;
146 WARN(
"[SDO::upload] [Restrictive] Uploaded just "<<(original_size-size)<<
" of "<<original_size<<
" bytes but there are no more segments. Ignore...");
162 for (
unsigned i=0; i<7; ++i) {
163 response.
data[i] = message.
data[1+i];
166 DEBUG_LOG(
"Received SDO (transmit/server) from node "<<(
unsigned)response.
node_id<<
". thread=" << std::this_thread::get_id()) ;
170 std::lock_guard<std::mutex> scoped_lock(m_send_and_wait_receiver_mutexes[response.
node_id]);
171 m_send_and_wait_receivers[response.
node_id](response);
180 DEBUG_LOG_EXHAUSTIVE(
"SDO::send_sdo_and_wait: thread=" << std::this_thread::get_id() <<
" node_id=" << node_id
181 <<
" command=" << command <<
" index=" << index <<
" subindex=" << subindex <<
" START.");
187 std::lock_guard<std::mutex> scoped_lock(m_send_and_wait_mutex[node_id]);
189 std::promise<SDOResponse> received_promise;
190 std::future<SDOResponse> received_future = received_promise.get_future();
193 std::lock_guard<std::mutex> scoped_lock(m_send_and_wait_receiver_mutexes[node_id]);
194 m_send_and_wait_receivers[node_id] = [&] (
SDOResponse response) {
199 received_promise.set_value(response);
205 message.
cob_id = 0x600+node_id;
208 message.
data[0] = command;
209 message.
data[1] = index & 0xFF;
210 message.
data[2] = (index >> 8) & 0xFF;
211 message.
data[3] = subindex;
212 message.
data[4] = data[0];
213 message.
data[5] = data[1];
214 message.
data[6] = data[2];
215 message.
data[7] = data[3];
216 m_core.
send(message);
218 DEBUG_LOG_EXHAUSTIVE(
"SDO::send_sdo_and_wait: thread=" << std::this_thread::get_id() <<
" node_id=" << node_id
219 <<
" command=" << command <<
" index=" << index <<
" subindex=" << subindex <<
" WAIT.");
222 const auto status = received_future.wait_for(timeout);
226 std::lock_guard<std::mutex> scoped_lock(m_send_and_wait_receiver_mutexes[node_id]);
227 m_send_and_wait_receivers[node_id] = received_unassigned_sdo;
230 if (status == std::future_status::timeout) {
231 DEBUG_LOG_EXHAUSTIVE(
"SDO::send_sdo_and_wait: thread=" << std::this_thread::get_id() <<
" node_id=" << node_id
232 <<
" command=" << command <<
" index=" << index <<
" subindex=" << subindex <<
" TIMEOUT.");
233 throw sdo_error(sdo_error::type::response_timeout,
"Timeout was "+std::to_string(timeout.count())+
"ms.");
236 DEBUG_LOG_EXHAUSTIVE(
"SDO::send_sdo_and_wait: thread=" << std::this_thread::get_id() <<
" node_id=" << node_id
237 <<
" command=" << command <<
" index=" << index <<
" subindex=" << subindex <<
" DONE.");
239 return received_future.get();
243 void SDO::received_unassigned_sdo(
SDOResponse response) {
244 DEBUG_LOG(
"Received unassigned SDO (transmit/server):");
245 DEBUG(response.
print();)
249 uint8_t SDO::size_flag(uint8_t size) {
258 assert(
false &&
"Dead code!");
uint16_t cob_id
Message ID aka COB-ID.
uint8_t len
Message's length (0 to 8)
SDO(Core &core)
Constructor.
void print() const
Prints the response to command line.
void send(const Message &message)
Sends a message.
uint8_t get_length() const
Returns the number of data bytes.
uint8_t failed() const
Check if the transfer failed.
void download(uint8_t node_id, uint16_t index, uint8_t subindex, uint32_t size, const std::vector< uint8_t > &bytes)
SDO download: Write value into remote device's object dictionary.
This type of exception is thrown when there are problems while accessing devices via SDO...
This struct contains the response of a SDO request. Note that there are two types of response - segme...
SDOResponse send_sdo_and_wait(uint8_t command, uint8_t node_id, uint16_t index, uint8_t subindex, const std::array< uint8_t, 4 > &data)
Sends an SDO message and waits for the response.
This class implements the Core of KaCanOpen It communicates with the CAN driver, sends CAN messages a...
static size_t sdo_response_timeout_ms
Timeout in milliseconds when waiting for an SDO response.
void process_incoming_message(const Message &message)
Process incoming SDO message.
uint8_t get_node_id() const
Extracts the node id from the COB-ID.
uint8_t command
SDO command specifier.
uint8_t rtr
Remote transmission request (0 if it's not an RTR message, 1 if it is an RTR message) ...
This struct represents a CANOpen message.
std::vector< uint8_t > upload(uint8_t node_id, uint16_t index, uint8_t subindex)
SDO download: Get value from remote device's object dictionary.
uint8_t data[8]
Data bytes.
uint32_t get_data() const
Returns the data as a single 4-byte value (only for expedited transfer).
uint8_t data[7]
Data bytes.