Lely core libraries 1.9.2
sdo.c
Go to the documentation of this file.
1
24#include "co.h"
25#define LELY_CO_SDO_INLINE extern inline
26#include <lely/util/errnum.h>
27#ifndef LELY_NO_CO_OBJ_FILE
28#include <lely/util/frbuf.h>
29#include <lely/util/fwbuf.h>
30#endif
31#include <lely/co/sdo.h>
32#include <lely/co/val.h>
33
34#include <assert.h>
35
50static int co_sdo_req_dn_buf(
51 struct co_sdo_req *req, const void **pptr, size_t *pnbyte);
52
54static void co_sdo_req_up_buf(struct co_sdo_req *req);
55
56const char *
57co_sdo_ac2str(co_unsigned32_t ac)
58{
59 switch (ac) {
60 case 0: return "Success";
61 case CO_SDO_AC_TOGGLE: return "Toggle bit not altered";
62 case CO_SDO_AC_TIMEOUT: return "SDO protocol timed out";
63 case CO_SDO_AC_NO_CS:
64 return "Client/server command specifier not valid or unknown";
65 case CO_SDO_AC_BLK_SIZE: return "Invalid block size";
66 case CO_SDO_AC_BLK_SEQ: return "Invalid sequence number";
67 case CO_SDO_AC_BLK_CRC: return "CRC error";
68 case CO_SDO_AC_NO_MEM: return "Out of memory";
69 case CO_SDO_AC_NO_ACCESS: return "Unsupported access to an object";
70 case CO_SDO_AC_NO_READ: return "Attempt to read a write only object";
71 case CO_SDO_AC_NO_WRITE: return "Attempt to write a read only object";
73 return "Object does not exist in the object dictionary";
74 case CO_SDO_AC_NO_PDO: return "Object cannot be mapped to the PDO";
76 return "The number and length of the objects to be mapped would exceed the PDO length";
77 case CO_SDO_AC_PARAM: return "General parameter incompatibility reason";
79 return "General internal incompatibility in the device";
80 case CO_SDO_AC_HARDWARE: return "Access failed due to a hardware error";
82 return "Data type does not match, length of service parameter does not match";
84 return "Data type does not match, length of service parameter too high";
86 return "Data type does not match, length of service parameter too low";
87 case CO_SDO_AC_NO_SUB: return "Sub-index does not exist";
88 case CO_SDO_AC_PARAM_VAL: return "Invalid value for parameter";
89 case CO_SDO_AC_PARAM_HI: return "Value of parameter written too high";
90 case CO_SDO_AC_PARAM_LO: return "Value of parameter written too low";
92 return "Maximum value is less than minimum value";
93 case CO_SDO_AC_NO_SDO: return "Resource not available: SDO connection";
94 case CO_SDO_AC_ERROR: return "General error";
95 case CO_SDO_AC_DATA:
96 return "Data cannot be transferred or stored to the application";
98 return "Data cannot be transferred or stored to the application because of local control";
100 return "Data cannot be transferred or stored to the application because of the present device state";
101 case CO_SDO_AC_NO_OD:
102 return "Object dictionary dynamic generation fails or no object dictionary is present";
103 case CO_SDO_AC_NO_DATA: return "No data available";
104 default: return "Unknown abort code";
105 }
106}
107
108void
110{
111 assert(req);
112
113 req->size = 0;
114 req->buf = NULL;
115 req->nbyte = 0;
116 req->offset = 0;
117 membuf_init(&req->membuf);
118}
119
120void
122{
123 assert(req);
124
125 membuf_fini(&req->membuf);
126}
127
128void
130{
131 req->size = 0;
132 req->buf = NULL;
133 req->nbyte = 0;
134 req->offset = 0;
135 membuf_clear(&req->membuf);
136}
137
138int
139co_sdo_req_dn(struct co_sdo_req *req, const void **pptr, size_t *pnbyte,
140 co_unsigned32_t *pac)
141{
142 co_unsigned32_t ac = 0;
143
144 int errc = get_errc();
145 switch (co_sdo_req_dn_buf(req, pptr, pnbyte)) {
146 default:
147 // Convert the error number to an SDO abort code.
148 // clang-format off
149 ac = get_errnum() == ERRNUM_NOMEM
151 // clang-format on
152 set_errc(errc);
153 // ...falls through ...
154 case 0:
155 // Return without an abort code if not all data is present. This
156 // is not an error.
157 if (pac)
158 *pac = ac;
159 return -1;
160 case 1: return 0;
161 }
162}
163
164int
165co_sdo_req_dn_val(struct co_sdo_req *req, co_unsigned16_t type, void *val,
166 co_unsigned32_t *pac)
167{
168 co_unsigned32_t ac = 0;
169
170 const void *ptr = NULL;
171 size_t nbyte = 0;
172 if (co_sdo_req_dn(req, &ptr, &nbyte, pac) == -1)
173 return -1;
174
175 // Read the value.
176 co_val_init(type, val);
177 size_t size = co_val_read(type, val, ptr, (const uint8_t *)ptr + nbyte);
178
179 // Check the size of the value.
180 if (co_type_is_array(type)) {
181 if (__unlikely(size != nbyte)) {
182 ac = CO_SDO_AC_NO_MEM;
183 goto error_read;
184 }
185 } else {
186 if (__unlikely(!size)) {
188 goto error_read;
189 } else if (__unlikely(size < nbyte)) {
191 goto error_read;
192 }
193 }
194
195 return 0;
196
197error_read:
198 co_val_fini(type, val);
199 if (pac)
200 *pac = ac;
201 return -1;
202}
203
204#ifndef LELY_NO_CO_OBJ_FILE
205int
206co_sdo_req_dn_file(struct co_sdo_req *req, const char *filename,
207 co_unsigned32_t *pac)
208{
209 int errc = get_errc();
210 co_unsigned32_t ac = 0;
211
212 const void *ptr = NULL;
213 size_t nbyte = 0;
214 if (co_sdo_req_dn(req, &ptr, &nbyte, pac) == -1)
215 return -1;
216
217 fwbuf_t *fbuf = fwbuf_create(filename);
218 if (__unlikely(!fbuf)) {
219 ac = CO_SDO_AC_DATA;
220 set_errc(errc);
221 goto error_create_fbuf;
222 }
223
224 if (__unlikely(fwbuf_write(fbuf, ptr, nbyte) != (ssize_t)nbyte)) {
225 ac = CO_SDO_AC_DATA;
226 set_errc(errc);
227 goto error_write;
228 }
229
230 if (__unlikely(fwbuf_commit(fbuf) == -1)) {
231 ac = CO_SDO_AC_DATA;
232 set_errc(errc);
233 goto error_commit;
234 }
235
236 fwbuf_destroy(fbuf);
237
238 return 0;
239
240error_commit:
241error_write:
242 fwbuf_destroy(fbuf);
243error_create_fbuf:
244 if (pac)
245 *pac = ac;
246 return -1;
247}
248#endif // !LELY_NO_CO_OBJ_FILE
249
250int
251co_sdo_req_up(struct co_sdo_req *req, const void *ptr, size_t n,
252 co_unsigned32_t *pac)
253{
254 assert(req);
255 struct membuf *buf = &req->membuf;
256
257 co_unsigned32_t ac = 0;
258
259 membuf_clear(buf);
260 if (__unlikely(n && !membuf_reserve(buf, n))) {
261 ac = CO_SDO_AC_NO_MEM;
262 goto error_reserve;
263 }
264
265 if (ptr)
266 membuf_write(buf, ptr, n);
267
269 return 0;
270
271error_reserve:
272 if (pac)
273 *pac = ac;
274 return -1;
275}
276
277int
278co_sdo_req_up_val(struct co_sdo_req *req, co_unsigned16_t type, const void *val,
279 co_unsigned32_t *pac)
280{
281 assert(req);
282 struct membuf *buf = &req->membuf;
283
284 co_unsigned32_t ac = 0;
285
286 size_t size = co_val_write(type, val, NULL, NULL);
287
288 membuf_clear(buf);
289 if (__unlikely(size && !membuf_reserve(buf, size))) {
290 ac = CO_SDO_AC_NO_MEM;
291 goto error_reserve;
292 }
293
294 uint8_t *begin = membuf_alloc(buf, &size);
295 if (__unlikely(co_val_write(type, val, begin, begin + size) != size)) {
296 ac = CO_SDO_AC_ERROR;
297 goto error_write;
298 }
299
301 return 0;
302
303error_write:
304error_reserve:
305 if (pac)
306 *pac = ac;
307 return -1;
308}
309
310#ifndef LELY_NO_CO_OBJ_FILE
311int
312co_sdo_req_up_file(struct co_sdo_req *req, const char *filename,
313 co_unsigned32_t *pac)
314{
315 assert(req);
316 struct membuf *buf = &req->membuf;
317
318 co_unsigned32_t ac = 0;
319
320 frbuf_t *fbuf = frbuf_create(filename);
321 if (__unlikely(!fbuf)) {
322 ac = CO_SDO_AC_DATA;
323 goto error_create_fbuf;
324 }
325
326 int64_t size = frbuf_get_size(fbuf);
327 if (__unlikely(size == -1)) {
328 ac = CO_SDO_AC_DATA;
329 goto error_get_size;
330 }
331 size_t nbyte = (size_t)size;
332
333 membuf_clear(buf);
334 if (__unlikely(size && !membuf_reserve(buf, nbyte))) {
335 ac = CO_SDO_AC_NO_MEM;
336 goto error_reserve;
337 }
338
339 void *ptr = membuf_alloc(buf, &nbyte);
340 if (__unlikely(frbuf_read(fbuf, ptr, nbyte) != (ssize_t)nbyte)) {
341 ac = CO_SDO_AC_DATA;
342 goto error_read;
343 }
344
345 frbuf_destroy(fbuf);
346
348 return 0;
349
350error_read:
351error_reserve:
352error_get_size:
353 frbuf_destroy(fbuf);
354error_create_fbuf:
355 if (pac)
356 *pac = ac;
357 return -1;
358}
359#endif // !LELY_NO_CO_OBJ_FILE
360
361static int
362co_sdo_req_dn_buf(struct co_sdo_req *req, const void **pptr, size_t *pnbyte)
363{
364 assert(req);
365 struct membuf *buf = &req->membuf;
366
367 // In case of an error, keep track of the offset with respect to the
368 // position indicator of the buffer.
369 ptrdiff_t offset = -(ptrdiff_t)membuf_size(buf);
370
371 const void *ptr;
372 if (co_sdo_req_first(req) && co_sdo_req_last(req)) {
373 // If the entire value is available right away, skip copying the
374 // data to the buffer.
375 ptr = req->buf;
376 } else {
377 if (co_sdo_req_first(req)) {
378 membuf_clear(buf);
379 // clang-format off
380 if (__unlikely(req->size
381 && !membuf_reserve(buf, req->size)))
382 // clang-format on
383 goto error_reserve;
384 } else {
385 // Adjust the offset if necessary. Only backtracking is
386 // allowed.
387 offset += req->offset;
388 if (offset) {
389 if (__unlikely(offset > 0)) {
391 goto error_offset;
392 }
393 membuf_seek(buf, offset);
394 }
395 }
396
397 if (req->nbyte) {
398 if (__unlikely(req->nbyte > membuf_capacity(buf))) {
400 goto error_nbyte;
401 }
402 membuf_write(buf, req->buf, req->nbyte);
403 }
404
405 if (!co_sdo_req_last(req))
406 return 0;
407
408 ptr = membuf_begin(buf);
409 }
410
411 if (pptr)
412 *pptr = ptr;
413 if (pnbyte)
414 *pnbyte = req->size;
415
416 return 1;
417
418error_nbyte:
419error_reserve:
420 // Restore the position indicator of the buffer.
421 membuf_seek(buf, -offset);
422error_offset:
423 return -1;
424}
425
426static void
428{
429 assert(req);
430 struct membuf *buf = &req->membuf;
431
432 req->size = membuf_size(buf);
433 req->buf = membuf_begin(buf);
434 req->nbyte = req->size;
435 req->offset = 0;
436}
This header file is part of the utilities library; it contains the native and platform-independent er...
@ ERRNUM_NOMEM
Not enough space.
Definition: errnum.h:169
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:129
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
errnum_t get_errnum(void)
Returns the last (thread-specific) platform-independent error number set by a system call or library ...
Definition: errnum.h:369
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
This header file is part of the utilities library; it contains the read file buffer declarations.
intmax_t frbuf_get_size(frbuf_t *buf)
Returns the size (in bytes) of the a read file buffer, or -1 on error.
Definition: frbuf.c:167
void frbuf_destroy(frbuf_t *buf)
Destroys a read file buffer.
Definition: frbuf.c:158
frbuf_t * frbuf_create(const char *filename)
Creates a new read file buffer.
Definition: frbuf.c:133
ssize_t frbuf_read(frbuf_t *buf, void *ptr, size_t size)
Reads bytes from the current position in a read file buffer.
Definition: frbuf.c:270
This header file is part of the utilities library; it contains the (atomic) write file buffer declara...
ssize_t fwbuf_write(fwbuf_t *buf, const void *ptr, size_t size)
Writes bytes to the current position in a write file buffer.
Definition: fwbuf.c:485
void fwbuf_destroy(fwbuf_t *buf)
Destroys a write file buffer.
Definition: fwbuf.c:326
int fwbuf_commit(fwbuf_t *buf)
Commits all changes to a write file buffer to disk if all previous file operations were successful,...
Definition: fwbuf.c:974
fwbuf_t * fwbuf_create(const char *filename)
Creates a new (atomic) write file buffer.
Definition: fwbuf.c:301
This header file is part of the CANopen library; it contains the Service Data Object (SDO) declaratio...
int co_sdo_req_first(const struct co_sdo_req *req)
Returns 1 if the specified request includes the first segment, and 0 otherwise.
Definition: sdo.h:340
#define CO_SDO_AC_TYPE_LEN_LO
SDO abort code: Data type does not match, length of service parameter too low.
Definition: sdo.h:129
#define CO_SDO_AC_PARAM_LO
SDO abort code: Value of parameter written too low (download only).
Definition: sdo.h:141
#define CO_SDO_AC_NO_READ
SDO abort code: Attempt to read a write only object.
Definition: sdo.h:87
#define CO_SDO_AC_NO_OD
SDO abort code: Object dictionary dynamic generation fails or no object dictionary is present (e....
Definition: sdo.h:172
#define CO_SDO_AC_TOGGLE
SDO abort code: Toggle bit not altered.
Definition: sdo.h:63
#define CO_SDO_AC_TYPE_LEN_HI
SDO abort code: Data type does not match, length of service parameter too high.
Definition: sdo.h:123
#define CO_SDO_AC_NO_CS
SDO abort code: Client/server command specifier not valid or unknown.
Definition: sdo.h:69
#define CO_SDO_AC_TYPE_LEN
SDO abort code: Data type does not match, length of service parameter does not match.
Definition: sdo.h:117
#define CO_SDO_AC_BLK_SEQ
SDO abort code: Invalid sequence number (block mode only).
Definition: sdo.h:75
#define CO_SDO_AC_NO_ACCESS
SDO abort code: Unsupported access to an object.
Definition: sdo.h:84
#define CO_SDO_AC_ERROR
SDO abort code: General error.
Definition: sdo.h:150
#define CO_SDO_AC_PARAM
SDO abort code: General parameter incompatibility reason.
Definition: sdo.h:105
#define CO_SDO_AC_DATA
SDO abort code: Data cannot be transferred or stored to the application.
Definition: sdo.h:153
#define CO_SDO_AC_HARDWARE
SDO abort code: Access failed due to a hardware error.
Definition: sdo.h:111
#define CO_SDO_AC_NO_SDO
SDO abort code: Resource not available: SDO connection.
Definition: sdo.h:147
#define CO_SDO_AC_DATA_DEV
SDO abort code: Data cannot be transferred or stored to the application because of the present device...
Definition: sdo.h:165
#define CO_SDO_AC_PARAM_HI
SDO abort code: Value of parameter written too high (download only).
Definition: sdo.h:138
#define CO_SDO_AC_NO_OBJ
SDO abort code: Object does not exist in the object dictionary.
Definition: sdo.h:93
#define CO_SDO_AC_NO_DATA
SDO abort code: No data available.
Definition: sdo.h:175
#define CO_SDO_AC_NO_SUB
SDO abort code: Sub-index does not exist.
Definition: sdo.h:132
#define CO_SDO_AC_BLK_SIZE
SDO abort code: Invalid block size (block mode only).
Definition: sdo.h:72
#define CO_SDO_AC_DATA_CTL
SDO abort code: Data cannot be transferred or stored to the application because of local control.
Definition: sdo.h:159
int co_sdo_req_last(const struct co_sdo_req *req)
Returns 1 if the specified request includes the last segment, and 0 otherwise.
Definition: sdo.h:346
#define CO_SDO_AC_PARAM_VAL
SDO abort code: Invalid value for parameter (download only).
Definition: sdo.h:135
#define CO_SDO_AC_PDO_LEN
SDO abort code: The number and length of the objects to be mapped would exceed the PDO length.
Definition: sdo.h:102
#define CO_SDO_AC_NO_PDO
SDO abort code: Object cannot be mapped to the PDO.
Definition: sdo.h:96
#define CO_SDO_AC_TIMEOUT
SDO abort code: SDO protocol timed out.
Definition: sdo.h:66
#define CO_SDO_AC_BLK_CRC
SDO abort code: CRC error (block mode only).
Definition: sdo.h:78
#define CO_SDO_AC_COMPAT
SDO abort code: General internal incompatibility in the device.
Definition: sdo.h:108
#define CO_SDO_AC_NO_MEM
SDO abort code: Out of memory.
Definition: sdo.h:81
#define CO_SDO_AC_NO_WRITE
SDO abort code: Attempt to write a read only object.
Definition: sdo.h:90
#define CO_SDO_AC_PARAM_RANGE
SDO abort code: Maximum value is less than minimum value (download only).
Definition: sdo.h:144
ptrdiff_t membuf_seek(struct membuf *buf, ptrdiff_t offset)
Adjusts the position indicator of a memory buffer by offset bytes.
Definition: membuf.h:168
void * membuf_begin(const struct membuf *buf)
Returns a pointer to the first byte in a memory buffer.
Definition: membuf.h:144
size_t membuf_reserve(struct membuf *buf, size_t size)
Resizes a memory buffer, if necessary, to make room for at least an additional size bytes.
Definition: membuf.c:46
void membuf_fini(struct membuf *buf)
Finalizes a memory buffer.
Definition: membuf.c:38
size_t membuf_capacity(const struct membuf *buf)
Returns the number of unused bytes remaining in a memory buffer.
Definition: membuf.h:162
size_t membuf_write(struct membuf *buf, const void *ptr, size_t size)
Writes data to a memory buffer.
Definition: membuf.h:192
void * membuf_alloc(struct membuf *buf, size_t *size)
Creates region of *size bytes in a memory buffer, starting at the current position indicator given by...
Definition: membuf.h:184
void membuf_clear(struct membuf *buf)
Clears a memory buffer.
Definition: membuf.h:150
void membuf_init(struct membuf *buf)
Initializes a memory buffer.
Definition: membuf.h:138
size_t membuf_size(const struct membuf *buf)
Returns the total number of bytes written to a memory buffer.
Definition: membuf.h:156
static void co_sdo_req_up_buf(struct co_sdo_req *req)
Constructs a CANopen SDO upload request from its internal buffer.
Definition: sdo.c:427
int co_sdo_req_dn_val(struct co_sdo_req *req, co_unsigned16_t type, void *val, co_unsigned32_t *pac)
Copies the next segment of the specified CANopen SDO download request to the internal buffer and,...
Definition: sdo.c:165
static int co_sdo_req_dn_buf(struct co_sdo_req *req, const void **pptr, size_t *pnbyte)
Copies the next segment of the specified CANopen SDO download request to the internal buffer.
Definition: sdo.c:362
int co_sdo_req_up_val(struct co_sdo_req *req, co_unsigned16_t type, const void *val, co_unsigned32_t *pac)
Writes the specified value to a buffer and constructs a CANopen SDO upload request.
Definition: sdo.c:278
int co_sdo_req_up(struct co_sdo_req *req, const void *ptr, size_t n, co_unsigned32_t *pac)
Writes the specified bytes to a buffer and constructs a CANopen SDO upload request.
Definition: sdo.c:251
void co_sdo_req_fini(struct co_sdo_req *req)
Finalizes a CANopen SDO upload/download request.
Definition: sdo.c:121
int co_sdo_req_dn_file(struct co_sdo_req *req, const char *filename, co_unsigned32_t *pac)
Copies the next segment of the specified CANopen SDO download request to the internal buffer and,...
Definition: sdo.c:206
int co_sdo_req_up_file(struct co_sdo_req *req, const char *filename, co_unsigned32_t *pac)
Loads the specified file into a buffer and constructs a CANopen SDO upload request.
Definition: sdo.c:312
void co_sdo_req_clear(struct co_sdo_req *req)
Clears a CANopen SDO upload/download request, including its buffer.
Definition: sdo.c:129
const char * co_sdo_ac2str(co_unsigned32_t ac)
Returns a string describing an SDO abort code.
Definition: sdo.c:57
void co_sdo_req_init(struct co_sdo_req *req)
Initializes a CANopen SDO upload/download request.
Definition: sdo.c:109
int co_sdo_req_dn(struct co_sdo_req *req, const void **pptr, size_t *pnbyte, co_unsigned32_t *pac)
Copies the next segment of the specified CANopen SDO download request to the internal buffer and,...
Definition: sdo.c:139
This is the internal header file of the CANopen library.
An read file buffer struct.
Definition: frbuf.c:49
An (atomic) write file buffer struct.
Definition: fwbuf.c:56
A CANopen SDO upload/download request.
Definition: sdo.h:178
size_t offset
The offset of the bytes at buf.
Definition: sdo.h:193
size_t size
The total size (in bytes) of the value to be uploaded/downloaded.
Definition: sdo.h:184
const void * buf
A pointer to the next bytes to be uploaded/downloaded.
Definition: sdo.h:186
struct membuf membuf
A memory buffer for use by the upload/download indication function.
Definition: sdo.h:199
size_t nbyte
The number of bytes available at buf.
Definition: sdo.h:188
A memory buffer.
Definition: membuf.h:35
char * begin
A pointer to the first byte in the buffer.
Definition: membuf.h:39
int co_type_is_array(co_unsigned16_t type)
Returns 1 if the specified (static) data type is an array, and 0 if not.
Definition: type.c:40
ptrdiff_t ssize_t
Used for a count of bytes or an error indication.
Definition: types.h:43
This header file is part of the CANopen library; it contains the CANopen value declarations.
size_t co_val_write(co_unsigned16_t type, const void *val, uint8_t *begin, uint8_t *end)
Writes a value of the specified data type to a memory buffer.
Definition: val.c:718
int co_val_init(co_unsigned16_t type, void *val)
Initializes a value of the specified data type to zero.
Definition: val.c:120
size_t co_val_read(co_unsigned16_t type, void *val, const uint8_t *begin, const uint8_t *end)
Reads a value of the specified data type from a memory buffer.
Definition: val.c:470
void co_val_fini(co_unsigned16_t type, void *val)
Finalizes a value of the specified data type.
Definition: val.c:273