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 
50 static int co_sdo_req_dn_buf(
51  struct co_sdo_req *req, const void **pptr, size_t *pnbyte);
52 
54 static void co_sdo_req_up_buf(struct co_sdo_req *req);
55 
56 const char *
57 co_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";
72  case CO_SDO_AC_NO_OBJ:
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";
75  case CO_SDO_AC_PDO_LEN:
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";
78  case CO_SDO_AC_COMPAT:
79  return "General internal incompatibility in the device";
80  case CO_SDO_AC_HARDWARE: return "Access failed due to a hardware error";
81  case CO_SDO_AC_TYPE_LEN:
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";
97  case CO_SDO_AC_DATA_CTL:
98  return "Data cannot be transferred or stored to the application because of local control";
99  case CO_SDO_AC_DATA_DEV:
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 
108 void
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 
120 void
122 {
123  assert(req);
124 
125  membuf_fini(&req->membuf);
126 }
127 
128 void
130 {
131  req->size = 0;
132  req->buf = NULL;
133  req->nbyte = 0;
134  req->offset = 0;
135  membuf_clear(&req->membuf);
136 }
137 
138 int
139 co_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 
164 int
165 co_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 
197 error_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
205 int
206 co_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 
240 error_commit:
241 error_write:
242  fwbuf_destroy(fbuf);
243 error_create_fbuf:
244  if (pac)
245  *pac = ac;
246  return -1;
247 }
248 #endif // !LELY_NO_CO_OBJ_FILE
249 
250 int
251 co_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 
268  co_sdo_req_up_buf(req);
269  return 0;
270 
271 error_reserve:
272  if (pac)
273  *pac = ac;
274  return -1;
275 }
276 
277 int
278 co_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 
300  co_sdo_req_up_buf(req);
301  return 0;
302 
303 error_write:
304 error_reserve:
305  if (pac)
306  *pac = ac;
307  return -1;
308 }
309 
310 #ifndef LELY_NO_CO_OBJ_FILE
311 int
312 co_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 
347  co_sdo_req_up_buf(req);
348  return 0;
349 
350 error_read:
351 error_reserve:
352 error_get_size:
353  frbuf_destroy(fbuf);
354 error_create_fbuf:
355  if (pac)
356  *pac = ac;
357  return -1;
358 }
359 #endif // !LELY_NO_CO_OBJ_FILE
360 
361 static int
362 co_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 
418 error_nbyte:
419 error_reserve:
420  // Restore the position indicator of the buffer.
421  membuf_seek(buf, -offset);
422 error_offset:
423  return -1;
424 }
425 
426 static 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 }
A CANopen SDO upload/download request.
Definition: sdo.h:178
#define CO_SDO_AC_NO_READ
SDO abort code: Attempt to read a write only object.
Definition: sdo.h:87
size_t membuf_write(struct membuf *buf, const void *ptr, size_t size)
Writes data to a memory buffer.
Definition: membuf.h:192
void co_sdo_req_fini(struct co_sdo_req *req)
Finalizes a CANopen SDO upload/download request.
Definition: sdo.c:121
#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
#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_DATA
SDO abort code: Data cannot be transferred or stored to the application.
Definition: sdo.h:153
#define CO_SDO_AC_BLK_SIZE
SDO abort code: Invalid block size (block mode only).
Definition: sdo.h:72
size_t size
The total size (in bytes) of the value to be uploaded/downloaded.
Definition: sdo.h:184
void co_sdo_req_init(struct co_sdo_req *req)
Initializes a CANopen SDO upload/download request.
Definition: sdo.c:109
#define CO_SDO_AC_NO_DATA
SDO abort code: No data available.
Definition: sdo.h:175
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
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
#define CO_SDO_AC_PARAM_VAL
SDO abort code: Invalid value for parameter (download only).
Definition: sdo.h:135
const char * co_sdo_ac2str(co_unsigned32_t ac)
Returns a string describing an SDO abort code.
Definition: sdo.c:57
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
#define CO_SDO_AC_ERROR
SDO abort code: General error.
Definition: sdo.h:150
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
This header file is part of the CANopen library; it contains the Service Data Object (SDO) declaratio...
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
#define CO_SDO_AC_BLK_CRC
SDO abort code: CRC error (block mode only).
Definition: sdo.h:78
#define CO_SDO_AC_NO_SDO
SDO abort code: Resource not available: SDO connection.
Definition: sdo.h:147
This header file is part of the CANopen library; it contains the CANopen value declarations.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
struct membuf membuf
A memory buffer for use by the upload/download indication function.
Definition: sdo.h:199
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
#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_TOGGLE
SDO abort code: Toggle bit not altered.
Definition: sdo.h:63
void * membuf_begin(const struct membuf *buf)
Returns a pointer to the first byte in a memory buffer.
Definition: membuf.h:144
This header file is part of the utilities library; it contains the native and platform-independent er...
char * begin
A pointer to the first byte in the buffer.
Definition: membuf.h:39
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 fwbuf_destroy(fwbuf_t *buf)
Destroys a write file buffer.
Definition: fwbuf.c:326
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
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
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
#define CO_SDO_AC_PARAM_RANGE
SDO abort code: Maximum value is less than minimum value (download only).
Definition: sdo.h:144
#define CO_SDO_AC_HARDWARE
SDO abort code: Access failed due to a hardware error.
Definition: sdo.h:111
#define CO_SDO_AC_TIMEOUT
SDO abort code: SDO protocol timed out.
Definition: sdo.h:66
frbuf_t * frbuf_create(const char *filename)
Creates a new read file buffer.
Definition: frbuf.c:133
This is the internal header file of the CANopen library.
fwbuf_t * fwbuf_create(const char *filename)
Creates a new (atomic) write file buffer.
Definition: fwbuf.c:301
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function...
Definition: errnum.c:947
#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
size_t membuf_capacity(const struct membuf *buf)
Returns the number of unused bytes remaining in a memory buffer.
Definition: membuf.h:162
An read file buffer struct.
Definition: frbuf.c:49
void frbuf_destroy(frbuf_t *buf)
Destroys a read file buffer.
Definition: frbuf.c:158
size_t offset
The offset of the bytes at buf.
Definition: sdo.h:193
Invalid argument.
Definition: errnum.h:129
A memory buffer.
Definition: membuf.h:35
#define CO_SDO_AC_NO_WRITE
SDO abort code: Attempt to write a read only object.
Definition: sdo.h:90
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
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
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
#define CO_SDO_AC_COMPAT
SDO abort code: General internal incompatibility in the device.
Definition: sdo.h:108
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
An (atomic) write file buffer struct.
Definition: fwbuf.c:56
#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_PARAM_LO
SDO abort code: Value of parameter written too low (download only).
Definition: sdo.h:141
void membuf_fini(struct membuf *buf)
Finalizes a memory buffer.
Definition: membuf.c:38
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
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_val_init(co_unsigned16_t type, void *val)
Initializes a value of the specified data type to zero.
Definition: val.c:120
void co_val_fini(co_unsigned16_t type, void *val)
Finalizes a value of the specified data type.
Definition: val.c:273
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
#define CO_SDO_AC_PARAM
SDO abort code: General parameter incompatibility reason.
Definition: sdo.h:105
#define CO_SDO_AC_NO_SUB
SDO abort code: Sub-index does not exist.
Definition: sdo.h:132
This header file is part of the utilities library; it contains the read file buffer declarations...
#define CO_SDO_AC_NO_MEM
SDO abort code: Out of memory.
Definition: sdo.h:81
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
#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
Not enough space.
Definition: errnum.h:169
size_t nbyte
The number of bytes available at buf.
Definition: sdo.h:188
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 void * buf
A pointer to the next bytes to be uploaded/downloaded.
Definition: sdo.h:186
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
This header file is part of the utilities library; it contains the (atomic) write file buffer declara...
#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
size_t membuf_size(const struct membuf *buf)
Returns the total number of bytes written to a memory buffer.
Definition: membuf.h:156
#define CO_SDO_AC_NO_ACCESS
SDO abort code: Unsupported access to an object.
Definition: sdo.h:84
#define CO_SDO_AC_BLK_SEQ
SDO abort code: Invalid sequence number (block mode only).
Definition: sdo.h:75
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
#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_TYPE_LEN
SDO abort code: Data type does not match, length of service parameter does not match.
Definition: sdo.h:117
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
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_NO_PDO
SDO abort code: Object cannot be mapped to the PDO.
Definition: sdo.h:96
#define CO_SDO_AC_NO_OBJ
SDO abort code: Object does not exist in the object dictionary.
Definition: sdo.h:93
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