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