Lely core libraries  1.9.2
dcf.c
Go to the documentation of this file.
1 
25 #include "co.h"
26 
27 #ifndef LELY_NO_CO_DCF
28 
29 #include "obj.h"
30 #include <lely/co/dcf.h>
31 #include <lely/co/pdo.h>
32 #include <lely/libc/strings.h>
33 #include <lely/libc/stdio.h>
34 #include <lely/util/config.h>
35 #include <lely/util/diag.h>
36 #include <lely/util/lex.h>
37 
38 #include <assert.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 static struct __co_dev *__co_dev_init_from_dcf_cfg(
43  struct __co_dev *dev, const config_t *cfg);
44 
45 static int co_dev_parse_cfg(co_dev_t *dev, const config_t *cfg);
46 
47 static int co_obj_parse_cfg(
48  co_obj_t *obj, const config_t *cfg, const char *section);
49 #ifndef LELY_NO_CO_OBJ_NAME
50 static int co_obj_parse_names(co_obj_t *obj, const config_t *cfg);
51 #endif
52 static int co_obj_parse_values(co_obj_t *obj, const config_t *cfg);
53 static co_obj_t *co_obj_build(co_dev_t *dev, co_unsigned16_t idx);
54 
55 static int co_sub_parse_cfg(
56  co_sub_t *sub, const config_t *cfg, const char *section);
57 static co_sub_t *co_sub_build(co_obj_t *obj, co_unsigned8_t subidx,
58  co_unsigned16_t type, const char *name);
59 
60 static int co_rpdo_build(co_dev_t *dev, co_unsigned16_t num, int mask);
61 static int co_tpdo_build(co_dev_t *dev, co_unsigned16_t num, int mask);
62 
63 static void co_val_set_id(co_unsigned16_t type, void *val, co_unsigned8_t id);
64 
65 static co_unsigned16_t config_get_idx(const config_t *cfg, const char *section,
66  co_unsigned16_t maxidx, co_unsigned16_t *idx);
67 
68 struct __co_dev *
69 __co_dev_init_from_dcf_file(struct __co_dev *dev, const char *filename)
70 {
72  if (__unlikely(!cfg)) {
74  "unable to create configuration struct");
75  goto error_create_cfg;
76  }
77 
78  if (__unlikely(!config_parse_ini_file(cfg, filename)))
79  goto error_parse_ini_file;
80 
81  if (__unlikely(!__co_dev_init_from_dcf_cfg(dev, cfg)))
82  goto error_init_dev;
83 
84  config_destroy(cfg);
85 
86  return dev;
87 
88 error_init_dev:
89 error_parse_ini_file:
90  config_destroy(cfg);
91 error_create_cfg:
92  return NULL;
93 }
94 
95 co_dev_t *
96 co_dev_create_from_dcf_file(const char *filename)
97 {
98  int errc = 0;
99 
100  co_dev_t *dev = __co_dev_alloc();
101  if (__unlikely(!dev)) {
102  errc = get_errc();
103  goto error_alloc_dev;
104  }
105 
106  if (__unlikely(!__co_dev_init_from_dcf_file(dev, filename))) {
107  errc = get_errc();
108  goto error_init_dev;
109  }
110 
111  return dev;
112 
113 error_init_dev:
114  __co_dev_free(dev);
115 error_alloc_dev:
116  set_errc(errc);
117  return NULL;
118 }
119 
120 struct __co_dev *
121 __co_dev_init_from_dcf_text(struct __co_dev *dev, const char *begin,
122  const char *end, struct floc *at)
123 {
125  if (__unlikely(!cfg)) {
127  "unable to create configuration struct");
128  goto error_create_cfg;
129  }
130 
131  if (__unlikely(!config_parse_ini_text(cfg, begin, end, at)))
132  goto error_parse_ini_text;
133 
134  if (__unlikely(!__co_dev_init_from_dcf_cfg(dev, cfg)))
135  goto error_init_dev;
136 
137  config_destroy(cfg);
138 
139  return dev;
140 
141 error_init_dev:
142 error_parse_ini_text:
143  config_destroy(cfg);
144 error_create_cfg:
145  return NULL;
146 }
147 
148 co_dev_t *
149 co_dev_create_from_dcf_text(const char *begin, const char *end, struct floc *at)
150 {
151  int errc = 0;
152 
153  co_dev_t *dev = __co_dev_alloc();
154  if (__unlikely(!dev)) {
155  errc = get_errc();
156  goto error_alloc_dev;
157  }
158 
159  if (__unlikely(!__co_dev_init_from_dcf_text(dev, begin, end, at))) {
160  errc = get_errc();
161  goto error_init_dev;
162  }
163 
164  return dev;
165 
166 error_init_dev:
167  __co_dev_free(dev);
168 error_alloc_dev:
169  set_errc(errc);
170  return NULL;
171 }
172 
173 static struct __co_dev *
174 __co_dev_init_from_dcf_cfg(struct __co_dev *dev, const config_t *cfg)
175 {
176  assert(dev);
177  assert(cfg);
178 
179  if (__unlikely(!__co_dev_init(dev, 0xff))) {
181  "unable to initialize device description");
182  goto error_init_dev;
183  }
184 
185  if (__unlikely(co_dev_parse_cfg(dev, cfg) == -1))
186  goto error_parse_cfg;
187 
188  return dev;
189 
190 error_parse_cfg:
191  __co_dev_fini(dev);
192 error_init_dev:
193  return NULL;
194 }
195 
196 static int
197 co_dev_parse_cfg(co_dev_t *dev, const config_t *cfg)
198 {
199  assert(dev);
200  assert(cfg);
201 
202  const char *val;
203 
204  // clang-format off
206  config_get(cfg, "DeviceInfo", "VendorName")) == -1)) {
207  // clang-format on
208  diag(DIAG_ERROR, get_errc(), "unable to set vendor name");
209  goto error_parse_dev;
210  }
211 
212  val = config_get(cfg, "DeviceInfo", "VendorNumber");
213  if (val && *val)
214  co_dev_set_vendor_id(dev, strtoul(val, NULL, 0));
215 
216  // clang-format off
218  config_get(cfg, "DeviceInfo", "ProductName")) == -1)) {
219  // clang-format on
220  diag(DIAG_ERROR, get_errc(), "unable to set product name");
221  goto error_parse_dev;
222  }
223 
224  val = config_get(cfg, "DeviceInfo", "ProductNumber");
225  if (val && *val)
226  co_dev_set_product_code(dev, strtoul(val, NULL, 0));
227 
228  val = config_get(cfg, "DeviceInfo", "RevisionNumber");
229  if (val && *val)
230  co_dev_set_revision(dev, strtoul(val, NULL, 0));
231 
232  // clang-format off
234  config_get(cfg, "DeviceInfo", "OrderCode")) == -1)) {
235  diag(DIAG_ERROR, get_errc(), "unable to set order code");
236  goto error_parse_dev;
237  // clang-format on
238  }
239 
240  unsigned int baud = 0;
241  val = config_get(cfg, "DeviceInfo", "BaudRate_10");
242  if (val && *val && strtoul(val, NULL, 0))
243  baud |= CO_BAUD_10;
244  val = config_get(cfg, "DeviceInfo", "BaudRate_20");
245  if (val && *val && strtoul(val, NULL, 0))
246  baud |= CO_BAUD_20;
247  val = config_get(cfg, "DeviceInfo", "BaudRate_50");
248  if (val && *val && strtoul(val, NULL, 0))
249  baud |= CO_BAUD_50;
250  val = config_get(cfg, "DeviceInfo", "BaudRate_125");
251  if (val && *val && strtoul(val, NULL, 0))
252  baud |= CO_BAUD_125;
253  val = config_get(cfg, "DeviceInfo", "BaudRate_250");
254  if (val && *val && strtoul(val, NULL, 0))
255  baud |= CO_BAUD_250;
256  val = config_get(cfg, "DeviceInfo", "BaudRate_500");
257  if (val && *val && strtoul(val, NULL, 0))
258  baud |= CO_BAUD_500;
259  val = config_get(cfg, "DeviceInfo", "BaudRate_800");
260  if (val && *val && strtoul(val, NULL, 0))
261  baud |= CO_BAUD_800;
262  val = config_get(cfg, "DeviceInfo", "BaudRate_1000");
263  if (val && *val && strtoul(val, NULL, 0))
264  baud |= CO_BAUD_1000;
265  co_dev_set_baud(dev, baud);
266 
267  val = config_get(cfg, "DeviceInfo", "LSS_Supported");
268  if (val && *val)
269  co_dev_set_lss(dev, strtoul(val, NULL, 0));
270 
271  // For each of the basic data types, check whether it is supported for
272  // mapping dummy entries in PDOs.
273  co_unsigned32_t dummy = 0;
274  for (int i = 0; i < 0x20; i++) {
275  // Create the key name.
276  char key[10];
277  sprintf(key, "Dummy%04X", (co_unsigned16_t)i);
278 
279  val = config_get(cfg, "DummyUsage", key);
280  if (val && *val && strtoul(val, NULL, 0))
281  dummy |= 1u << i;
282  }
283  co_dev_set_dummy(dev, dummy);
284 
285  // Count the total number of objects.
286  co_unsigned16_t n = 0;
287  n += config_get_idx(cfg, "MandatoryObjects", 0, NULL);
288  n += config_get_idx(cfg, "OptionalObjects", 0, NULL);
289  n += config_get_idx(cfg, "ManufacturerObjects", 0, NULL);
290 
291  // Parse the object indices.
292  co_unsigned16_t *idx = malloc(n * sizeof(co_unsigned16_t));
293  if (__unlikely(!idx)) {
294  diag(DIAG_ERROR, errno2c(errno),
295  "unable to create object list");
296  goto error_parse_idx;
297  }
298  co_unsigned16_t i = 0;
299  i += config_get_idx(cfg, "MandatoryObjects", n - i, idx + i);
300  i += config_get_idx(cfg, "OptionalObjects", n - i, idx + i);
301  config_get_idx(cfg, "ManufacturerObjects", n - i, idx + i);
302 
303  for (i = 0; i < n; i++) {
304  if (__unlikely(!idx[i])) {
305  diag(DIAG_ERROR, 0, "entry (%d) missing in object list",
306  i);
307  goto error_parse_obj;
308  }
309 
310  // Create the section name for the object.
311  char section[5];
312  sprintf(section, "%X", idx[i]);
313 
314  // Create the object and add it to the dictionary.
315  co_obj_t *obj = co_obj_build(dev, idx[i]);
316  if (__unlikely(!obj))
317  goto error_parse_obj;
318 
319  // Parse the configuration section for the object.
320  if (__unlikely(co_obj_parse_cfg(obj, cfg, section) == -1))
321  goto error_parse_obj;
322  }
323 
324  if (!co_dev_find_obj(dev, 0x1000))
325  diag(DIAG_WARNING, 0, "mandatory object 0x1000 missing");
326  if (!co_dev_find_obj(dev, 0x1001))
327  diag(DIAG_WARNING, 0, "mandatory object 0x1001 missing");
328  if (!co_dev_find_obj(dev, 0x1018))
329  diag(DIAG_WARNING, 0, "mandatory object 0x1018 missing");
330 
331  // Parse compact PDO definitions after the explicit object definitions
332  // to prevent overwriting PDOs.
333  val = config_get(cfg, "DeviceInfo", "CompactPDO");
334  if (val && *val) {
335  unsigned int mask = strtoul(val, NULL, 0);
336 
337  co_unsigned16_t nrpdo = 0;
338  val = config_get(cfg, "DeviceInfo", "NrOfRxPDO");
339  if (val && *val)
340  nrpdo = (co_unsigned16_t)strtoul(val, NULL, 0);
341  for (co_unsigned16_t num = 1; num <= nrpdo; num++) {
342  if (__unlikely(co_rpdo_build(dev, num, mask) == -1))
343  goto error_parse_pdo;
344  }
345 
346  co_unsigned16_t ntpdo = 0;
347  val = config_get(cfg, "DeviceInfo", "NrOfTxPDO");
348  if (val && *val)
349  ntpdo = (co_unsigned16_t)strtoul(val, NULL, 0);
350  for (co_unsigned16_t num = 1; num <= ntpdo; num++) {
351  if (__unlikely(co_tpdo_build(dev, num, mask) == -1))
352  goto error_parse_pdo;
353  }
354  }
355 
356  val = config_get(cfg, "DeviceComissioning", "NodeID");
357  // clang-format off
358  if (val && *val && co_dev_set_id(dev,
359  (co_unsigned8_t)strtoul(val, NULL, 0)) == -1) {
360  // clang-format on
361  diag(DIAG_ERROR, get_errc(), "invalid node-ID (%s) specified",
362  val);
363  goto error_parse_dcf;
364  }
365 
366  val = config_get(cfg, "DeviceComissioning", "NetNumber");
367  // clang-format off
368  if (val && *val && co_dev_set_netid(dev,
369  (co_unsigned32_t)strtoul(val, NULL, 0)) == -1) {
370  // clang-format on
372  "invalid network-ID (%s) specified", val);
373  goto error_parse_dcf;
374  }
375 
376  // clang-format off
377  if (__unlikely(co_dev_set_name(dev,
378  config_get(cfg, "DeviceComissioning", "NodeName"))
379  == -1)) {
380  // clang-format on
381  diag(DIAG_ERROR, get_errc(), "unable to set node name");
382  goto error_parse_dcf;
383  }
384 
385  val = config_get(cfg, "DeviceComissioning", "Baudrate");
386  if (val && *val)
387  co_dev_set_rate(dev, (co_unsigned16_t)strtoul(val, NULL, 0));
388 
389  val = config_get(cfg, "DeviceComissioning", "LSS_SerialNumber");
390  // clang-format off
391  if (val && *val && !co_dev_set_val_u32(dev, 0x1018, 0x04,
392  strtoul(val, NULL, 0))) {
393  // clang-format on
394  diag(DIAG_ERROR, get_errc(), "unable to set serial number");
395  goto error_parse_dcf;
396  }
397 
398  free(idx);
399 
400  return 0;
401 
402 error_parse_pdo:
403 error_parse_dcf:
404 error_parse_obj:
405  free(idx);
406 error_parse_idx:
407 error_parse_dev:
408  return -1;
409 }
410 
411 static int
412 co_obj_parse_cfg(co_obj_t *obj, const config_t *cfg, const char *section)
413 {
414  assert(obj);
415  assert(cfg);
416 
417  const char *val;
418  struct floc at = { section, 0, 0 };
419 
420  co_unsigned16_t idx = co_obj_get_idx(obj);
421 
422  const char *name = config_get(cfg, section, "ParameterName");
423  if (__unlikely(!name || !*name)) {
424  diag(DIAG_ERROR, 0,
425  "ParameterName not specified for object 0x%04X",
426  idx);
427  return -1;
428  }
429 #ifndef LELY_NO_CO_OBJ_NAME
430  val = config_get(cfg, section, "Denotation");
431  if (val && *val)
432  name = val;
433  if (__unlikely(co_obj_set_name(obj, name) == -1)) {
435  "unable to set name of object 0x%04X", idx);
436  return -1;
437  }
438 #endif
439 
440  co_unsigned8_t code = co_obj_get_code(obj);
441  val = config_get(cfg, section, "ObjectType");
442  if (val && *val) {
443  code = (co_unsigned8_t)strtoul(val, NULL, 0);
444  if (__unlikely(co_obj_set_code(obj, code) == -1)) {
445  diag(DIAG_ERROR, 0,
446  "ObjectType = 0x%x for object 0x%04X",
447  code, idx);
448  return -1;
449  }
450  }
451 
452  if (code == CO_OBJECT_DEFSTRUCT || code == CO_OBJECT_ARRAY
453  || code == CO_OBJECT_RECORD) {
454  co_unsigned8_t subnum = 0;
455  val = config_get(cfg, section, "SubNumber");
456  if (val && *val)
457  subnum = (co_unsigned8_t)strtoul(val, NULL, 0);
458  co_unsigned8_t subobj = 0;
459  val = config_get(cfg, section, "CompactSubObj");
460  if (val && *val)
461  subobj = (co_unsigned8_t)strtoul(val, NULL, 0);
462  if (__unlikely(!subnum && !subobj)) {
463  diag(DIAG_ERROR, 0,
464  "neither SubNumber nor CompactSubObj specified for object 0x%04X",
465  idx);
466  return -1;
467  }
468  if (__unlikely(subnum && subobj)) {
469  diag(DIAG_ERROR, 0,
470  "both SubNumber and CompactSubObj specified for object 0x%04X",
471  idx);
472  return -1;
473  }
474 
475  // Parse the sub-objects specified by SubNumber.
476  for (size_t subidx = 0; subnum && subidx < 0xff; subidx++) {
477  // Create section name for the sub-object.
478  char section[10];
479  sprintf(section, "%Xsub%X", (co_unsigned16_t)idx,
480  (co_unsigned8_t)subidx);
481 
482  // Check whether the sub-index exists by checking the
483  // presence of the mandatory ParameterName keyword.
484  const char *name = config_get(
485  cfg, section, "ParameterName");
486  if (!name || !*name)
487  continue;
488  subnum--;
489 
490  // The Denonation entry, if it exists, overrides
491  // ParameterName.
492  val = config_get(cfg, section, "Denotation");
493  if (val && *val)
494  name = val;
495 
496  // Obtain the data type of the sub-object.
497  val = config_get(cfg, section, "DataType");
498  if (!val || !*val) {
499  diag_at(DIAG_ERROR, 0, &at,
500  "DataType not specified");
501  return -1;
502  }
503  co_unsigned16_t type =
504  (co_unsigned16_t)strtoul(val, NULL, 0);
505 
506  // Create and insert the sub-object.
507  co_sub_t *sub = co_sub_build(obj,
508  (co_unsigned8_t)subidx, type, name);
509  if (__unlikely(!sub))
510  return -1;
511 
512  // Parse the configuration section for the sub-object.
513  // clang-format off
514  if (__unlikely(co_sub_parse_cfg(sub, cfg, section)
515  == -1))
516  // clang-format on
517  return -1;
518  }
519 
520  // Create an array based on CompactSubObj.
521  if (subobj) {
522  co_sub_t *sub = co_sub_build(obj, 0,
523  CO_DEFTYPE_UNSIGNED8, "NrOfObjects");
524  if (__unlikely(!sub))
525  return -1;
526  co_val_make(sub->type, &sub->def, &subobj,
527  sizeof(subobj));
528  co_val_copy(sub->type, sub->val, &sub->def);
530 
531  name = config_get(cfg, section, "ParameterName");
532 
533  // Obtain the data type of the sub-object.
534  val = config_get(cfg, section, "DataType");
535  if (!val || !*val) {
536  diag_at(DIAG_ERROR, 0, &at,
537  "DataType not specified");
538  return -1;
539  }
540  co_unsigned16_t type =
541  (co_unsigned16_t)strtoul(val, NULL, 0);
542 
543  // Create the sub-objects.
544  for (size_t subidx = 1; subidx <= subobj; subidx++) {
545  // Create name of the sub-object.
546  char *subname = NULL;
547  // clang-format off
548  if (__unlikely(asprintf(&subname, "%s%u", name,
549  (co_unsigned8_t)subidx) < 0))
550  // clang-format on
551  return -1;
552 
553  // Create and insert the sub-object.
554  sub = co_sub_build(obj, (co_unsigned8_t)subidx,
555  type, subname);
556  free(subname);
557  if (__unlikely(!sub))
558  return -1;
559 
560  // Parse the configuration section for the
561  // sub-object.
562  // clang-format off
563  if (__unlikely(co_sub_parse_cfg(sub, cfg,
564  section) == -1))
565  // clang-format on
566  return -1;
567  }
568 
569 #ifndef LELY_NO_CO_OBJ_NAME
570  // Parse the names of the sub-objects.
571  if (__unlikely(co_obj_parse_names(obj, cfg) == -1))
572  return -1;
573 #endif
574 
575  // Parse the values of the sub-objects.
576  if (__unlikely(co_obj_parse_values(obj, cfg) == -1))
577  return -1;
578  }
579 
580  co_sub_t *sub = co_obj_find_sub(obj, 0x00);
581  // clang-format off
582  if (__unlikely(!sub || co_sub_get_type(sub)
583  != CO_DEFTYPE_UNSIGNED8)) {
584  // clang-format on
585  diag(DIAG_ERROR, 0,
586  "object 0x%04X does not provide the highest sub-index implemented",
587  idx);
588  return -1;
589  }
590  } else {
591  // Obtain the data type of the object (optional for DOMAIN
592  // objects).
593  co_unsigned16_t type = code == CO_OBJECT_DOMAIN
595  : 0;
596  val = config_get(cfg, section, "DataType");
597  if (val && *val)
598  type = (co_unsigned16_t)strtoul(val, NULL, 0);
599  if (__unlikely(!type)) {
600  diag_at(DIAG_ERROR, 0, &at, "DataType not specified");
601  return -1;
602  }
603 
604  // Create and insert the sub-object.
605  co_sub_t *sub = co_sub_build(obj, 0, type, name);
606  if (__unlikely(!sub))
607  return -1;
608 
609  // Parse the configuration section for the sub-object.
610  if (__unlikely(co_sub_parse_cfg(sub, cfg, section) == -1))
611  return -1;
612  }
613 
614  return 0;
615 }
616 
617 #ifndef LELY_NO_CO_OBJ_NAME
618 static int
619 co_obj_parse_names(co_obj_t *obj, const config_t *cfg)
620 {
621  assert(obj);
622  assert(cfg);
623 
624  co_unsigned16_t idx = co_obj_get_idx(obj);
625 
626  // Create the section name for the explicit names of the sub-objects.
627  char section[9];
628  sprintf(section, "%XName", idx);
629 
630  const char *val = config_get(cfg, section, "NrOfEntries");
631  if (!val || !*val)
632  return 0;
633 
634  co_unsigned8_t n = (co_unsigned8_t)strtoul(val, NULL, 0);
635  for (size_t subidx = 1; n && subidx < 0xff; subidx++) {
636  char key[4];
637  sprintf(key, "%u", (co_unsigned8_t)subidx);
638 
639  val = config_get(cfg, section, key);
640  if (val && *val) {
641  n--;
642  co_sub_t *sub = co_obj_find_sub(
643  obj, (co_unsigned8_t)subidx);
644  // clang-format off
645  if (sub && __unlikely(co_sub_set_name(sub, val)
646  == -1)) {
647  // clang-format on
649  "unable to set name of sub-object %Xsub%X",
650  (co_unsigned16_t)idx,
651  (co_unsigned8_t)subidx);
652  return -1;
653  }
654  }
655  }
656 
657  return 0;
658 }
659 #endif // LELY_NO_CO_OBJ_NAME
660 
661 static int
662 co_obj_parse_values(co_obj_t *obj, const config_t *cfg)
663 {
664  assert(obj);
665  assert(cfg);
666 
667  co_unsigned8_t id = co_dev_get_id(co_obj_get_dev(obj));
668  co_unsigned16_t idx = co_obj_get_idx(obj);
669 
670  // Create the section name for the explicit values of the sub-objects.
671  char section[10];
672  sprintf(section, "%XValue", (co_unsigned16_t)idx);
673  struct floc at = { section, 0, 0 };
674 
675  const char *val = config_get(cfg, section, "NrOfEntries");
676  if (!val || !*val)
677  return 0;
678 
679  co_unsigned8_t n = (co_unsigned8_t)strtoul(val, NULL, 0);
680  for (size_t subidx = 1; n && subidx < 0xff; subidx++) {
681  char key[4];
682  sprintf(key, "%u", (co_unsigned8_t)subidx);
683 
684  val = config_get(cfg, section, key);
685  if (val && *val) {
686  n--;
687  co_sub_t *sub = co_obj_find_sub(
688  obj, (co_unsigned8_t)subidx);
689  co_unsigned16_t type = co_sub_get_type(sub);
690  co_val_fini(type, sub->val);
691  if (!strncmp(val, "$NODEID", 7)) {
692  val += 7;
694  }
695  // clang-format off
696  if (__unlikely(!co_val_lex(
697  type, sub->val, val, NULL, &at))) {
698  // clang-format on
700  "unable to set value of sub-object %Xsub%X",
701  (co_unsigned16_t)idx,
702  (co_unsigned8_t)subidx);
703  return -1;
704  }
705  if (sub->flags & CO_OBJ_FLAGS_VAL_NODEID)
706  co_val_set_id(type, sub->val, id);
707  }
708  }
709 
710  return 0;
711 }
712 
713 static co_obj_t *
714 co_obj_build(co_dev_t *dev, co_unsigned16_t idx)
715 {
716  assert(dev);
717 
718  co_obj_t *obj = co_obj_create(idx);
719  if (__unlikely(!obj)) {
720  diag(DIAG_ERROR, get_errc(), "unable to create object 0x%04X",
721  idx);
722  return NULL;
723  }
724 
725  if (__unlikely(co_dev_insert_obj(dev, obj) == -1)) {
726  diag(DIAG_ERROR, 0,
727  "unable to insert object 0x%04X into the object dictionary",
728  idx);
729  co_obj_destroy(obj);
730  return NULL;
731  }
732 
733  return obj;
734 }
735 
736 static int
737 co_sub_parse_cfg(co_sub_t *sub, const config_t *cfg, const char *section)
738 {
739  assert(sub);
740  assert(cfg);
741 
742  const char *val;
743  struct floc at = { section, 0, 0 };
744 
745  co_unsigned8_t id = co_dev_get_id(co_obj_get_dev(co_sub_get_obj(sub)));
746  co_unsigned16_t type = co_sub_get_type(sub);
747 
748 #ifndef LELY_NO_CO_OBJ_LIMITS
749  val = config_get(cfg, section, "LowLimit");
750  if (val && *val) {
751  if (!strncmp(val, "$NODEID", 7)) {
752  val += 7;
754  }
755  if (__unlikely(!co_val_lex(type, &sub->min, val, NULL, &at))) {
756  diag_at(DIAG_ERROR, get_errc(), &at,
757  "unable to parse LowLimit");
758  return -1;
759  }
760  if (sub->flags & CO_OBJ_FLAGS_MIN_NODEID)
761  co_val_set_id(type, &sub->min, id);
762  }
763 
764  val = config_get(cfg, section, "HighLimit");
765  if (val && *val) {
766  if (!strncmp(val, "$NODEID", 7)) {
767  val += 7;
769  }
770  if (__unlikely(!co_val_lex(type, &sub->max, val, NULL, &at))) {
771  diag_at(DIAG_ERROR, get_errc(), &at,
772  "unable to parse HighLimit");
773  return -1;
774  }
775  if (sub->flags & CO_OBJ_FLAGS_MAX_NODEID)
776  co_val_set_id(type, &sub->max, id);
777  }
778 #endif // LELY_NO_CO_OBJ_LIMITS
779 
780  unsigned int access = co_sub_get_access(sub);
781  val = config_get(cfg, section, "AccessType");
782  if (val && *val) {
783  if (!strcasecmp(val, "ro")) {
784  access = CO_ACCESS_RO;
785  } else if (!strcasecmp(val, "wo")) {
786  access = CO_ACCESS_WO;
787  } else if (!strcasecmp(val, "rw")) {
788  access = CO_ACCESS_RW;
789  } else if (!strcasecmp(val, "rwr")) {
790  access = CO_ACCESS_RWR;
791  } else if (!strcasecmp(val, "rww")) {
792  access = CO_ACCESS_RWW;
793  } else if (!strcasecmp(val, "const")) {
794  access = CO_ACCESS_CONST;
795  } else {
796  diag_at(DIAG_ERROR, 0, &at, "AccessType = %s", val);
797  return -1;
798  }
799  co_sub_set_access(sub, access);
800  } else if (type != CO_DEFTYPE_DOMAIN) {
801  diag_at(DIAG_ERROR, 0, &at, "AccessType not specified");
802  return -1;
803  }
804 
805  val = config_get(cfg, section, "DefaultValue");
806  if (val && *val) {
807  if (!strncmp(val, "$NODEID", 7)) {
808  val += 7;
810  }
811  if (__unlikely(!co_val_lex(type, &sub->def, val, NULL, &at))) {
812  diag_at(DIAG_ERROR, get_errc(), &at,
813  "unable to parse DefaultValue");
814  return -1;
815  }
816  if (sub->flags & CO_OBJ_FLAGS_DEF_NODEID)
817  co_val_set_id(type, &sub->def, id);
818  }
819 
820  val = config_get(cfg, section, "PDOMapping");
821  if (val && *val)
822  co_sub_set_pdo_mapping(sub, strtoul(val, NULL, 0));
823 
824  val = config_get(cfg, section, "ObjFlags");
825  if (val && *val)
826  sub->flags |= strtoul(val, NULL, 0);
827 
828  val = config_get(cfg, section, "ParameterValue");
829  if (val && *val) {
830  if (!strncmp(val, "$NODEID", 7)) {
831  val += 7;
833  }
834  if (__unlikely(!co_val_lex(type, sub->val, val, NULL, &at))) {
835  diag_at(DIAG_ERROR, get_errc(), &at,
836  "unable to parse ParameterValue");
837  return -1;
838  }
839  if (sub->flags & CO_OBJ_FLAGS_VAL_NODEID)
840  co_val_set_id(type, sub->val, id);
841 #ifndef LELY_NO_CO_OBJ_FILE
842  } else if (type == CO_DEFTYPE_DOMAIN
843  && (val = config_get(cfg, section, "UploadFile"))
844  != NULL) {
845  if (!(access & CO_ACCESS_READ) || (access & CO_ACCESS_WRITE)) {
846  diag_at(DIAG_WARNING, 0, &at,
847  "AccessType must be 'ro' or 'const' when using UploadFile");
848  access |= CO_ACCESS_READ;
849  access &= ~CO_ACCESS_WRITE;
850  co_sub_set_access(sub, access);
851  }
852 
854  // Store the filename instead of its contents in the object
855  // dictionary.
856  // clang-format off
857  if (__unlikely(co_val_init_dom(sub->val, val, strlen(val) + 1)
858  == -1)) {
859  // clang-format on
860  diag_at(DIAG_ERROR, get_errc(), &at,
861  "unable to parse UploadFile");
862  return -1;
863  }
864  } else if (type == CO_DEFTYPE_DOMAIN
865  && (val = config_get(cfg, section, "DownloadFile"))
866  != NULL) {
867  if ((access & CO_ACCESS_READ) || !(access & CO_ACCESS_WRITE)) {
868  diag_at(DIAG_WARNING, 0, &at,
869  "AccessType must be 'wo' when using DownloadFile");
870  access &= ~CO_ACCESS_READ;
871  access |= CO_ACCESS_WRITE;
872  co_sub_set_access(sub, access);
873  }
875  // Store the filename instead of its contents in the object
876  // dictionary.
877  // clang-format off
878  if (__unlikely(co_val_init_dom(sub->val, val, strlen(val) + 1)
879  == -1)) {
880  // clang-format on
881  diag_at(DIAG_ERROR, get_errc(), &at,
882  "unable to parse DownloadFile");
883  return -1;
884  }
885 #endif
886  } else {
887  if (sub->flags & CO_OBJ_FLAGS_DEF_NODEID)
889  co_val_copy(type, sub->val, &sub->def);
890  }
891 
892 #ifndef LELY_NO_CO_OBJ_LIMITS
893  if (co_type_is_basic(type)) {
894  const void *min = co_sub_addressof_min(sub);
895  const void *max = co_sub_addressof_max(sub);
896  const void *def = co_sub_addressof_def(sub);
897  const void *val = co_sub_addressof_val(sub);
898  if (co_val_cmp(type, min, max) > 0)
899  diag_at(DIAG_WARNING, 0, &at,
900  "LowLimit exceeds HighLimit");
901  if (co_val_cmp(type, def, min) < 0)
902  diag_at(DIAG_WARNING, 0, &at, "DefaultValue underflow");
903  if (co_val_cmp(type, def, max) > 0)
904  diag_at(DIAG_WARNING, 0, &at, "DefaultValue overflow");
905  if (co_val_cmp(type, val, def)
906  && co_val_cmp(type, val, min) < 0)
907  diag_at(DIAG_WARNING, 0, &at,
908  "ParameterValue underflow");
909  if (co_val_cmp(type, val, def)
910  && co_val_cmp(type, val, max) > 0)
911  diag_at(DIAG_WARNING, 0, &at,
912  "ParameterValue overflow");
913  }
914 #endif
915 
916  return 0;
917 }
918 
919 static co_sub_t *
920 co_sub_build(co_obj_t *obj, co_unsigned8_t subidx, co_unsigned16_t type,
921  const char *name)
922 {
923  assert(obj);
924 
925  co_unsigned16_t idx = co_obj_get_idx(obj);
926 
927  co_sub_t *sub = co_sub_create(subidx, type);
928  if (__unlikely(!sub)) {
930  "unable to create sub-object %Xsub%X", idx,
931  subidx);
932  goto error;
933  }
934 
935  if (__unlikely(co_obj_insert_sub(obj, sub) == -1)) {
936  diag(DIAG_ERROR, 0,
937  "unable to insert sub-object %Xsub%X into the object dictionary",
938  idx, subidx);
939  goto error;
940  }
941 
942 #ifndef LELY_NO_CO_OBJ_NAME
943  if (__unlikely(co_sub_set_name(sub, name) == -1)) {
945  "unable to set name of sub-object %Xsub%X", idx,
946  subidx);
947  goto error;
948  }
949 #else
950  (void)name;
951 #endif
952 
953  return sub;
954 
955 error:
956  co_sub_destroy(sub);
957  return NULL;
958 }
959 
960 static int
961 co_rpdo_build(co_dev_t *dev, co_unsigned16_t num, int mask)
962 {
963  assert(dev);
964  assert(num && num <= 512);
965 
966  // Find the highest sub-index supported.
967  mask &= 0x3f;
968  co_unsigned8_t n = 0;
969  for (int i = 0; i < 6; i++) {
970  if (mask & (1 << i))
971  n = i + 1;
972  }
973 
974  // Create the RPDO communication parameter if it does not exist.
975  if (!co_dev_find_obj(dev, 0x1400 + num - 1)) {
976  co_obj_t *obj = co_obj_build(dev, 0x1400 + num - 1);
977  if (__unlikely(!obj))
978  return -1;
979 #ifndef LELY_NO_CO_OBJ_NAME
980  // clang-format off
981  if (__unlikely(co_obj_set_name(obj,
982  "RPDO communication parameter") == -1)) {
983  // clang-format on
984  diag(DIAG_ERROR, get_errc(), "unable configure RPDO %u",
985  num);
986  return -1;
987  }
988 #endif
990 
991  co_sub_t *sub = co_sub_build(obj, 0, CO_DEFTYPE_UNSIGNED8,
992  "Highest sub-index supported");
993  if (__unlikely(!sub))
994  return -1;
995  co_val_make(sub->type, &sub->def, &n, sizeof(n));
996  co_val_copy(sub->type, sub->val, &sub->def);
998 
999  if (mask & 0x01) {
1000  sub = co_sub_build(obj, 1, CO_DEFTYPE_UNSIGNED32,
1001  "COB-ID used by RPDO");
1002  if (__unlikely(!sub))
1003  return -1;
1004  co_unsigned32_t cobid = CO_PDO_COBID_VALID;
1005  if (num <= 4) {
1006  cobid = num * 0x100 + 0x100 + 0xff;
1009  }
1010  co_val_make(sub->type, &sub->def, &cobid,
1011  sizeof(cobid));
1012  co_val_copy(sub->type, sub->val, &sub->def);
1014  }
1015 
1016  if (mask & 0x02) {
1017  sub = co_sub_build(obj, 2, CO_DEFTYPE_UNSIGNED8,
1018  "Transmission type");
1019  if (__unlikely(!sub))
1020  return -1;
1022  }
1023 
1024  if (mask & 0x04) {
1025  sub = co_sub_build(obj, 3, CO_DEFTYPE_UNSIGNED16,
1026  "Inhibit time");
1027  if (__unlikely(!sub))
1028  return -1;
1030  }
1031 
1032  if (mask & 0x08) {
1033  sub = co_sub_build(obj, 4, CO_DEFTYPE_UNSIGNED8,
1034  "Compatibility entry");
1035  if (__unlikely(!sub))
1036  return -1;
1038  }
1039 
1040  if (mask & 0x10) {
1041  sub = co_sub_build(obj, 5, CO_DEFTYPE_UNSIGNED16,
1042  "Event timer");
1043  if (__unlikely(!sub))
1044  return -1;
1046  }
1047 
1048  if (mask & 0x20) {
1049  sub = co_sub_build(obj, 6, CO_DEFTYPE_UNSIGNED8,
1050  "SYNC start value");
1051  if (__unlikely(!sub))
1052  return -1;
1054  }
1055  }
1056 
1057  // Create the RPDO mapping parameter if it does not exist.
1058  if (!co_dev_find_obj(dev, 0x1600 + num - 1)) {
1059  co_obj_t *obj = co_obj_build(dev, 0x1600 + num - 1);
1060  if (__unlikely(!obj))
1061  return -1;
1062 #ifndef LELY_NO_CO_OBJ_NAME
1063  // clang-format off
1064  if (__unlikely(co_obj_set_name(obj, "RPDO mapping parameter")
1065  == -1)) {
1066  // clang-format on
1067  diag(DIAG_ERROR, get_errc(), "unable configure RPDO %u",
1068  num);
1069  return -1;
1070  }
1071 #endif
1073 
1074  co_sub_t *sub = co_sub_build(obj, 0, CO_DEFTYPE_UNSIGNED8,
1075  "Highest sub-index supported");
1076  if (__unlikely(!sub))
1077  return -1;
1079 
1080  for (co_unsigned8_t i = 1; i <= 0x40; i++) {
1081  char name[22];
1082  sprintf(name, "Application object %u", i);
1083 
1084  co_sub_t *sub = co_sub_build(
1085  obj, i, CO_DEFTYPE_UNSIGNED32, name);
1086  if (__unlikely(!sub))
1087  return -1;
1089  }
1090  }
1091 
1092  return 0;
1093 }
1094 
1095 static int
1096 co_tpdo_build(co_dev_t *dev, co_unsigned16_t num, int mask)
1097 {
1098  assert(dev);
1099  assert(num && num <= 512);
1100 
1101  // Find the highest sub-index supported.
1102  mask &= 0x3f;
1103  co_unsigned8_t n = 0;
1104  for (int i = 0; i < 6; i++) {
1105  if (mask & (1 << i))
1106  n = i + 1;
1107  }
1108 
1109  // Create the TPDO communication parameter if it does not exist.
1110  if (!co_dev_find_obj(dev, 0x1800 + num - 1)) {
1111  co_obj_t *obj = co_obj_build(dev, 0x1800 + num - 1);
1112  if (__unlikely(!obj))
1113  return -1;
1114 #ifndef LELY_NO_CO_OBJ_NAME
1115  // clang-format off
1116  if (__unlikely(co_obj_set_name(obj,
1117  "TPDO communication parameter") == -1)) {
1118  // clang-format on
1119  diag(DIAG_ERROR, get_errc(), "unable configure TPDO %u",
1120  num);
1121  return -1;
1122  }
1123 #endif
1125 
1126  co_sub_t *sub = co_sub_build(obj, 0, CO_DEFTYPE_UNSIGNED8,
1127  "Highest sub-index supported");
1128  if (__unlikely(!sub))
1129  return -1;
1130  co_val_make(sub->type, &sub->def, &n, sizeof(n));
1131  co_val_copy(sub->type, sub->val, &sub->def);
1133 
1134  if (mask & 0x01) {
1135  sub = co_sub_build(obj, 1, CO_DEFTYPE_UNSIGNED32,
1136  "COB-ID used by TPDO");
1137  if (__unlikely(!sub))
1138  return -1;
1139  co_unsigned32_t cobid = CO_PDO_COBID_VALID;
1140  if (num <= 4) {
1141  cobid = num * 0x100 + 0x80 + 0xff;
1144  }
1145  co_val_make(sub->type, &sub->def, &cobid,
1146  sizeof(cobid));
1147  co_val_copy(sub->type, sub->val, &sub->def);
1149  }
1150 
1151  if (mask & 0x02) {
1152  sub = co_sub_build(obj, 2, CO_DEFTYPE_UNSIGNED8,
1153  "Transmission type");
1154  if (__unlikely(!sub))
1155  return -1;
1157  }
1158 
1159  if (mask & 0x04) {
1160  sub = co_sub_build(obj, 3, CO_DEFTYPE_UNSIGNED16,
1161  "Inhibit time");
1162  if (__unlikely(!sub))
1163  return -1;
1165  }
1166 
1167  if (mask & 0x08) {
1168  sub = co_sub_build(obj, 4, CO_DEFTYPE_UNSIGNED8,
1169  "Reserved");
1170  if (__unlikely(!sub))
1171  return -1;
1173  }
1174 
1175  if (mask & 0x10) {
1176  sub = co_sub_build(obj, 5, CO_DEFTYPE_UNSIGNED16,
1177  "Event timer");
1178  if (__unlikely(!sub))
1179  return -1;
1181  }
1182 
1183  if (mask & 0x20) {
1184  sub = co_sub_build(obj, 6, CO_DEFTYPE_UNSIGNED8,
1185  "SYNC start value");
1186  if (__unlikely(!sub))
1187  return -1;
1189  }
1190  }
1191 
1192  // Create the TPDO mapping parameter if it does not exist.
1193  if (!co_dev_find_obj(dev, 0x1a00 + num - 1)) {
1194  co_obj_t *obj = co_obj_build(dev, 0x1a00 + num - 1);
1195  if (__unlikely(!obj))
1196  return -1;
1197 #ifndef LELY_NO_CO_OBJ_NAME
1198  // clang-format off
1199  if (__unlikely(co_obj_set_name(obj, "TPDO mapping parameter")
1200  == -1)) {
1201  // clang-format on
1202  diag(DIAG_ERROR, get_errc(), "unable configure TPDO %u",
1203  num);
1204  return -1;
1205  }
1206 #endif
1208 
1209  co_sub_t *sub = co_sub_build(obj, 0, CO_DEFTYPE_UNSIGNED8,
1210  "Highest sub-index supported");
1211  if (__unlikely(!sub))
1212  return -1;
1214 
1215  for (co_unsigned8_t i = 1; i <= 0x40; i++) {
1216  char name[22];
1217  sprintf(name, "Application object %u", i);
1218 
1219  co_sub_t *sub = co_sub_build(
1220  obj, i, CO_DEFTYPE_UNSIGNED32, name);
1221  if (__unlikely(!sub))
1222  return -1;
1224  }
1225  }
1226 
1227  return 0;
1228 }
1229 
1230 static void
1231 co_val_set_id(co_unsigned16_t type, void *val, co_unsigned8_t id)
1232 {
1233  assert(val);
1234 
1235  union co_val *u = val;
1236  switch (type) {
1237 #define LELY_CO_DEFINE_TYPE(a, b, c, d) \
1238  case CO_DEFTYPE_##a: \
1239  u->c += id; \
1240  break;
1241 #include <lely/co/def/basic.def>
1242 #undef LELY_CO_DEFINE_TYPE
1243  }
1244 }
1245 
1246 static co_unsigned16_t
1247 config_get_idx(const config_t *cfg, const char *section, co_unsigned16_t maxidx,
1248  co_unsigned16_t *idx)
1249 {
1250  assert(cfg);
1251 
1252  if (!idx)
1253  maxidx = 0;
1254 
1255  const char *val = config_get(cfg, section, "SupportedObjects");
1256  if (__unlikely(!val || !*val))
1257  return 0;
1258 
1259  co_unsigned16_t n = (co_unsigned16_t)strtoul(val, NULL, 0);
1260  for (size_t i = 0; i < (size_t)MIN(n, maxidx); i++) {
1261  char key[6];
1262  sprintf(key, "%u", (co_unsigned16_t)(i + 1));
1263 
1264  val = config_get(cfg, section, key);
1265  // clang-format off
1266  idx[i] = val && *val
1267  ? (co_unsigned16_t)strtoul(val, NULL, 0) : 0;
1268  // clang-format on
1269  }
1270 
1271  return n;
1272 }
1273 
1274 #endif // !LELY_NO_CO_DCF
#define CO_ACCESS_RWW
Read or write on process output.
Definition: obj.h:81
void co_dev_set_revision(co_dev_t *dev, co_unsigned32_t revision)
Sets the revision number of a CANopen device.
Definition: dev.c:427
int co_obj_insert_sub(co_obj_t *obj, co_sub_t *sub)
Inserts a sub-object into a CANopen object.
Definition: obj.c:164
#define CO_OBJ_FLAGS_UPLOAD_FILE
If a read access is performed for the object, the data is stored in a file.
Definition: obj.h:96
void co_dev_set_lss(co_dev_t *dev, int lss)
Sets the LSS support flag.
Definition: dev.c:505
#define CO_BAUD_20
A bit rate of 20 kbit/s.
Definition: dev.h:77
void co_dev_set_dummy(co_dev_t *dev, co_unsigned32_t dummy)
Sets the data types supported by a CANopen device for mapping dummy entries in PDOs.
Definition: dev.c:521
#define CO_OBJECT_DOMAIN
A large variable amount of data.
Definition: obj.h:33
#define CO_BAUD_10
A bit rate of 10 kbit/s.
Definition: dev.h:80
This header file is part of the C11 and POSIX compatibility library; it includes <strings.h>, if it exists, and defines any missing functionality.
size_t config_parse_ini_text(config_t *config, const char *begin, const char *end, struct floc *at)
Parses a string in INI-format and adds the keys to a configuration struct.
Definition: config_ini.c:75
A CANopen sub-object.
Definition: obj.h:54
#define CO_ACCESS_WRITE
The object can be written.
Definition: obj.h:60
This header file is part of the C11 and POSIX compatibility library; it includes <string.h> and defines any missing functionality.
#define CO_ACCESS_WO
Write-only access.
Definition: obj.h:72
const void * co_sub_addressof_max(const co_sub_t *sub)
Returns the address of the upper limit of the value of a CANopen sub-object.
Definition: obj.c:545
#define CO_BAUD_500
A bit rate of 500 kbit/s.
Definition: dev.h:65
co_unsigned16_t type
The data type.
Definition: obj.h:62
#define CO_DEFTYPE_DOMAIN
The data type (and object index) of an arbitrary large block of data.
Definition: type.h:77
A location in a text file.
Definition: diag.h:31
int co_sub_set_name(co_sub_t *sub, const char *name)
Sets the name of a CANopen sub-object.
Definition: obj.c:484
int asprintf(char **strp, const char *fmt,...)
Equivalent to sprintf(), except that it allocates a string large enough to hold the output...
Definition: stdio.c:103
int co_val_init_dom(void **val, const void *dom, size_t n)
Initializes an arbitrary large block of data (CO_DEFTYPE_DOMAIN).
Definition: val.c:254
int co_obj_set_code(co_obj_t *obj, co_unsigned8_t code)
Sets the code (type) of a CANopen object.
Definition: obj.c:258
#define CO_OBJ_FLAGS_DOWNLOAD_FILE
If a write access is performed for the object, the data is stored in a file.
Definition: obj.h:102
co_dev_t * co_dev_create_from_dcf_file(const char *filename)
Creates a CANopen device from an EDS or DCF file.
Definition: dcf.c:96
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
Section and key names are case-insensitive.
Definition: config.h:37
unsigned flags
The object flags.
Definition: obj.h:82
#define CO_ACCESS_RWR
Read or write on process input.
Definition: obj.h:78
A union of the CANopen static data types.
Definition: val.h:163
co_obj_t * co_obj_create(co_unsigned16_t idx)
Creates a CANopen object.
Definition: obj.c:106
This header file is part of the utilities library; it contains the configuration functions.
co_unsigned8_t co_dev_get_id(const co_dev_t *dev)
Returns the node-ID of a CANopen device.
Definition: dev.c:198
#define MIN(a, b)
Returns the minimum of a and b.
Definition: util.h:57
union co_val max
The upper limit of the object value.
Definition: obj.h:71
A configuration struct.
Definition: config.c:35
co_unsigned8_t co_obj_get_code(const co_obj_t *obj)
Returns the object code of a CANopen object.
Definition: obj.c:250
#define CO_BAUD_50
A bit rate of 50 kbit/s.
Definition: dev.h:74
union co_val min
The lower limit of the object value.
Definition: obj.h:69
void co_dev_set_product_code(co_dev_t *dev, co_unsigned32_t product_code)
Sets the product code of a CANopen device.
Definition: dev.c:411
int co_dev_set_vendor_name(co_dev_t *dev, const char *vendor_name)
Sets the vendor name of a CANopen device.
Definition: dev.c:335
This is the internal header file of the object dictionary.
unsigned baud
The supported bit rates.
Definition: dev.c:60
void co_sub_destroy(co_sub_t *sub)
Destroys a CANopen sub-object.
Definition: obj.c:449
const void * co_sub_addressof_min(const co_sub_t *sub)
Returns the address of the lower limit of the value of a CANopen sub-object.
Definition: obj.c:518
char * name
A pointer to the name of the device.
Definition: dev.c:46
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
const void * co_sub_addressof_def(const co_sub_t *sub)
Returns the address of the default value of a CANopen sub-object.
Definition: obj.c:574
unsigned int co_sub_get_access(const co_sub_t *sub)
Returns the access type of a CANopen sub-object.
Definition: obj.c:682
#define CO_OBJECT_RECORD
A multiple data field object where the data fields may be any combination of simple variables...
Definition: obj.h:54
union co_val def
The default value.
Definition: obj.h:74
#define CO_ACCESS_READ
The object can be read.
Definition: obj.h:57
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50
void config_destroy(config_t *config)
Destroys a configuration struct.
Definition: config.c:135
void * val
A pointer to the sub-object value.
Definition: obj.h:76
int co_dev_set_netid(co_dev_t *dev, co_unsigned8_t id)
Sets the network-ID of a CANopen device.
Definition: dev.c:183
#define CO_ACCESS_RO
Read-only access.
Definition: obj.h:69
#define CO_BAUD_125
A bit rate of 125 kbit/s.
Definition: dev.h:71
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition: type.h:47
#define CO_ACCESS_CONST
Constant value.
Definition: obj.h:84
int co_type_is_basic(co_unsigned16_t type)
Returns 1 if the specified (static) data type is a basic type, and 0 if not.
Definition: type.c:28
This is the internal header file of the CANopen library.
void co_sub_set_pdo_mapping(co_sub_t *sub, int pdo_mapping)
Enables or disables PDO mapping a CANopen sub-object.
Definition: obj.c:714
#define CO_ACCESS_RW
Read or write access.
Definition: obj.h:75
This header file is part of the utilities library; it contains the lexer function declarations...
#define CO_PDO_COBID_VALID
The bit in the PDO COB-ID specifying whether the PDO exists and is valid.
Definition: pdo.h:28
int co_dev_insert_obj(co_dev_t *dev, co_obj_t *obj)
Inserts an object into the object dictionary of a CANopen device.
Definition: dev.c:243
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function...
Definition: errnum.c:947
co_dev_t * co_obj_get_dev(const co_obj_t *obj)
Returns a pointer to the CANopen device containing the specified object.
Definition: obj.c:128
int co_dev_set_order_code(co_dev_t *dev, const char *order_code)
Sets the order code of a CANopen device.
Definition: dev.c:443
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition: type.h:44
co_dev_t * co_dev_create_from_dcf_text(const char *begin, const char *end, struct floc *at)
Creates a CANopen device from an EDS or DCF text string.
Definition: dcf.c:149
size_t co_val_copy(co_unsigned16_t type, void *dst, const void *src)
Copies one value to another.
Definition: val.c:333
void co_dev_set_rate(co_dev_t *dev, co_unsigned16_t rate)
Sets the (pending) baudrate of a CANopen device.
Definition: dev.c:489
co_unsigned32_t dummy
The data types supported for mapping dummy entries in PDOs.
Definition: dev.c:66
An error.
Definition: diag.h:49
#define CO_BAUD_250
A bit rate of 250 kbit/s.
Definition: dev.h:68
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
This header file is part of the utilities library; it contains the diagnostic declarations.
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
const char * config_get(const config_t *config, const char *section, const char *key)
Retrieves a key from a configuration struct.
Definition: config.c:188
#define CO_OBJ_FLAGS_VAL_NODEID
The current object value is of the form $NODEID { "+" number }.
Definition: obj.h:114
size_t co_val_make(co_unsigned16_t type, void *val, const void *ptr, size_t n)
Constructs a value of the specified data type.
Definition: val.c:306
int co_val_cmp(co_unsigned16_t type, const void *v1, const void *v2)
Compares two values of the specified data type.
Definition: val.c:386
A CANopen device.
Definition: dev.c:38
void diag_at(enum diag_severity severity, int errc, const struct floc *at, const char *format,...)
Emits a diagnostic message occurring at a location in a text file.
Definition: diag.c:172
co_obj_t * co_sub_get_obj(const co_sub_t *sub)
Returns the a pointer to the CANopen object containing the specified sub-object.
Definition: obj.c:458
size_t co_val_lex(co_unsigned16_t type, void *val, const char *begin, const char *end, struct floc *at)
Lexes a value of the specified data type from a memory buffer.
Definition: val.c:869
This header file is part of the C11 and POSIX compatibility library; it includes <stdio.h> and defines any missing functionality.
const void * co_sub_addressof_val(const co_sub_t *sub)
Returns the address of the current value of a CANopen sub-object.
Definition: obj.c:601
void co_obj_destroy(co_obj_t *obj)
Destroys a CANopen object, including its sub-objects.
Definition: obj.c:118
#define CO_OBJECT_DEFSTRUCT
A record type definition.
Definition: obj.h:39
A warning.
Definition: diag.h:47
void co_val_fini(co_unsigned16_t type, void *val)
Finalizes a value of the specified data type.
Definition: val.c:273
int co_sub_set_access(co_sub_t *sub, unsigned int access)
Sets the access type of a CANopen sub-object.
Definition: obj.c:690
co_sub_t * co_sub_create(co_unsigned8_t subidx, co_unsigned16_t type)
Creates a CANopen sub-object.
Definition: obj.c:424
int co_dev_set_product_name(co_dev_t *dev, const char *product_name)
Sets the product name of a CANopen device.
Definition: dev.c:381
int co_obj_set_name(co_obj_t *obj, const char *name)
Sets the name of a CANopen object.
Definition: obj.c:226
#define CO_OBJ_FLAGS_DEF_NODEID
The default object value is of the form $NODEID { "+" number }.
Definition: obj.h:111
int co_dev_set_id(co_dev_t *dev, co_unsigned8_t id)
Sets the node-ID of a CANopen device.
Definition: dev.c:206
void co_dev_set_baud(co_dev_t *dev, unsigned int baud)
Sets the supported bit rates of a CANopen device.
Definition: dev.c:473
#define CO_BAUD_800
A bit rate of 800 kbit/s.
Definition: dev.h:62
size_t config_parse_ini_file(config_t *config, const char *filename)
Parses an INI file and adds the keys to a configuration struct.
Definition: config_ini.c:47
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
#define CO_BAUD_1000
A bit rate of 1 Mbit/s.
Definition: dev.h:59
co_obj_t * co_dev_find_obj(const co_dev_t *dev, co_unsigned16_t idx)
Finds an object in the object dictionary of a CANopen device.
Definition: dev.c:279
co_unsigned16_t co_sub_get_type(const co_sub_t *sub)
Returns the data type of a CANopen sub-object.
Definition: obj.c:508
co_sub_t * co_obj_find_sub(const co_obj_t *obj, co_unsigned8_t subidx)
Finds a sub-object in a CANopen object.
Definition: obj.c:207
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition: obj.c:136
config_t * config_create(int flags)
Creates a new configuration struct with an unnamed empty root section.
Definition: config.c:110
#define CO_OBJ_FLAGS_MAX_NODEID
The upper limit of the object value is of the form $NODEID { "+" number }.
Definition: obj.h:108
int co_dev_set_name(co_dev_t *dev, const char *name)
Sets the name of a CANopen device.
Definition: dev.c:305
A CANopen object.
Definition: obj.h:32
#define CO_OBJ_FLAGS_MIN_NODEID
The lower limit of the object value is of the form $NODEID { "+" number }.
Definition: obj.h:105
This header file is part of the CANopen library; it contains the Electronic Data Sheet (EDS) and Devi...
#define CO_OBJECT_ARRAY
A multiple data field object where each data field is a simple variable of the same basic data type...
Definition: obj.h:48
void co_dev_set_vendor_id(co_dev_t *dev, co_unsigned32_t vendor_id)
Sets the vendor ID of a CANopen device.
Definition: dev.c:365
This header file is part of the CANopen library; it contains the Process Data Object (PDO) declaratio...