Lely core libraries  2.2.5
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/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 #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 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  diag(DIAG_ERROR, errno2c(errno),
299  "unable to create object list");
300  goto error_parse_idx;
301  }
302  co_unsigned16_t i = 0;
303  i += config_get_idx(cfg, "MandatoryObjects", n - i, idx + i);
304  i += config_get_idx(cfg, "OptionalObjects", n - i, idx + i);
305  config_get_idx(cfg, "ManufacturerObjects", n - i, idx + i);
306 
307  for (i = 0; i < n; i++) {
308  if (!idx[i]) {
309  diag(DIAG_ERROR, 0, "entry (%d) missing in object list",
310  i);
311  goto error_parse_obj;
312  }
313 
314  // Create the section name for the object.
315  char section[5];
316  snprintf(section, sizeof(section), "%X", idx[i]);
317 
318  // Create the object and add it to the dictionary.
319  co_obj_t *obj = co_obj_build(dev, idx[i]);
320  if (!obj)
321  goto error_parse_obj;
322 
323  // Parse the configuration section for the object.
324  if (co_obj_parse_cfg(obj, cfg, section) == -1)
325  goto error_parse_obj;
326  }
327 
328  if (!co_dev_find_obj(dev, 0x1000))
329  diag(DIAG_WARNING, 0, "mandatory object 0x1000 missing");
330  if (!co_dev_find_obj(dev, 0x1001))
331  diag(DIAG_WARNING, 0, "mandatory object 0x1001 missing");
332  if (!co_dev_find_obj(dev, 0x1018))
333  diag(DIAG_WARNING, 0, "mandatory object 0x1018 missing");
334 
335  // Parse compact PDO definitions after the explicit object definitions
336  // to prevent overwriting PDOs.
337  val = config_get(cfg, "DeviceInfo", "CompactPDO");
338  unsigned int mask = val && *val ? strtoul(val, NULL, 0) : 0;
339  if (mask) {
340  co_unsigned16_t nrpdo = 0;
341  val = config_get(cfg, "DeviceInfo", "NrOfRxPDO");
342  if (val && *val)
343  nrpdo = (co_unsigned16_t)strtoul(val, NULL, 0);
344  // Count the number of implicit RPDOs.
345  for (co_unsigned16_t i = 0; i < 512 && nrpdo; i++) {
346  if (co_dev_find_obj(dev, 0x1400 + i)
347  || co_dev_find_obj(dev, 0x1600 + i))
348  nrpdo--;
349  }
350  for (co_unsigned16_t i = 0; i < 512; i++) {
351  if (!co_dev_find_obj(dev, 0x1400 + i)
352  && !co_dev_find_obj(dev, 0x1600 + i)) {
353  if (!nrpdo)
354  continue;
355  nrpdo--;
356  }
357  // Add missing communication and/or mapping objects.
358  if (co_rpdo_build(dev, i + 1, mask) == -1)
359  goto error_parse_pdo;
360  }
361 
362  co_unsigned16_t ntpdo = 0;
363  val = config_get(cfg, "DeviceInfo", "NrOfTxPDO");
364  if (val && *val)
365  ntpdo = (co_unsigned16_t)strtoul(val, NULL, 0);
366  // Count the number of implicit TPDOs.
367  for (co_unsigned16_t i = 0; i < 512 && ntpdo; i++) {
368  if (co_dev_find_obj(dev, 0x1800 + i)
369  || co_dev_find_obj(dev, 0x1a00 + i))
370  ntpdo--;
371  }
372  for (co_unsigned16_t i = 0; i < 512; i++) {
373  if (!co_dev_find_obj(dev, 0x1800 + i)
374  && !co_dev_find_obj(dev, 0x1a00 + i)) {
375  if (!ntpdo)
376  continue;
377  ntpdo--;
378  }
379  // Add missing communication and/or mapping objects.
380  if (co_tpdo_build(dev, i + 1, mask) == -1)
381  goto error_parse_pdo;
382  }
383  }
384 
385  val = config_get(cfg, "DeviceComissioning", "NodeID");
386  // clang-format off
387  if (val && *val && co_dev_set_id(dev,
388  (co_unsigned8_t)strtoul(val, NULL, 0)) == -1) {
389  // clang-format on
390  diag(DIAG_ERROR, get_errc(), "invalid node-ID (%s) specified",
391  val);
392  goto error_parse_dcf;
393  }
394 
395  val = config_get(cfg, "DeviceComissioning", "NetNumber");
396  // clang-format off
397  if (val && *val && co_dev_set_netid(dev,
398  (co_unsigned32_t)strtoul(val, NULL, 0)) == -1) {
399  // clang-format on
401  "invalid network-ID (%s) specified", val);
402  goto error_parse_dcf;
403  }
404 
405  // clang-format off
406  if (co_dev_set_name(dev,
407  config_get(cfg, "DeviceComissioning", "NodeName"))
408  == -1) {
409  // clang-format on
410  diag(DIAG_ERROR, get_errc(), "unable to set node name");
411  goto error_parse_dcf;
412  }
413 
414  val = config_get(cfg, "DeviceComissioning", "Baudrate");
415  if (val && *val)
416  co_dev_set_rate(dev, (co_unsigned16_t)strtoul(val, NULL, 0));
417 
418  val = config_get(cfg, "DeviceComissioning", "LSS_SerialNumber");
419  // clang-format off
420  if (val && *val && !co_dev_set_val_u32(dev, 0x1018, 0x04,
421  strtoul(val, NULL, 0))) {
422  // clang-format on
423  diag(DIAG_ERROR, get_errc(), "unable to set serial number");
424  goto error_parse_dcf;
425  }
426 
427  free(idx);
428 
429  return 0;
430 
431 error_parse_pdo:
432 error_parse_dcf:
433 error_parse_obj:
434  free(idx);
435 error_parse_idx:
436 error_parse_dev:
437  return -1;
438 }
439 
440 static int
441 co_obj_parse_cfg(co_obj_t *obj, const config_t *cfg, const char *section)
442 {
443  assert(obj);
444  assert(cfg);
445 
446  const char *val;
447  struct floc at = { section, 0, 0 };
448 
449  co_unsigned16_t idx = co_obj_get_idx(obj);
450 
451  const char *name = config_get(cfg, section, "ParameterName");
452  if (!name) {
453  diag(DIAG_ERROR, 0,
454  "ParameterName not specified for object 0x%04X",
455  idx);
456  return -1;
457  }
458 #ifndef LELY_NO_CO_OBJ_NAME
459  val = config_get(cfg, section, "Denotation");
460  if (val && *val)
461  name = val;
462  if (co_obj_set_name(obj, name) == -1) {
464  "unable to set name of object 0x%04X", idx);
465  return -1;
466  }
467 #endif
468 
469  co_unsigned8_t code = co_obj_get_code(obj);
470  val = config_get(cfg, section, "ObjectType");
471  if (val && *val) {
472  code = (co_unsigned8_t)strtoul(val, NULL, 0);
473  if (co_obj_set_code(obj, code) == -1) {
474  diag(DIAG_ERROR, 0,
475  "ObjectType = 0x%x for object 0x%04X",
476  code, idx);
477  return -1;
478  }
479  }
480 
481  if (code == CO_OBJECT_DEFSTRUCT || code == CO_OBJECT_ARRAY
482  || code == CO_OBJECT_RECORD) {
483  co_unsigned8_t subnum = 0;
484  val = config_get(cfg, section, "SubNumber");
485  if (val && *val)
486  subnum = (co_unsigned8_t)strtoul(val, NULL, 0);
487  co_unsigned8_t subobj = 0;
488  val = config_get(cfg, section, "CompactSubObj");
489  if (val && *val)
490  subobj = (co_unsigned8_t)strtoul(val, NULL, 0);
491  if (!subnum && !subobj) {
492  diag(DIAG_ERROR, 0,
493  "neither SubNumber nor CompactSubObj specified for object 0x%04X",
494  idx);
495  return -1;
496  }
497  if (subnum && subobj) {
498  diag(DIAG_ERROR, 0,
499  "both SubNumber and CompactSubObj specified for object 0x%04X",
500  idx);
501  return -1;
502  }
503 
504  // Parse the sub-objects specified by SubNumber.
505  for (size_t subidx = 0; subnum && subidx < 0xff; subidx++) {
506  // Create section name for the sub-object.
507  char section[10];
508  snprintf(section, sizeof(section), "%Xsub%X",
509  (co_unsigned16_t)idx,
510  (co_unsigned8_t)subidx);
511 
512  // Check whether the sub-index exists by checking the
513  // presence of the mandatory ParameterName keyword.
514  const char *name = config_get(
515  cfg, section, "ParameterName");
516  if (!name)
517  continue;
518  subnum--;
519 
520  // The Denonation entry, if it exists, overrides
521  // ParameterName.
522  val = config_get(cfg, section, "Denotation");
523  if (val && *val)
524  name = val;
525 
526  // Obtain the data type of the sub-object.
527  val = config_get(cfg, section, "DataType");
528  if (!val || !*val) {
529  diag_at(DIAG_ERROR, 0, &at,
530  "DataType not specified");
531  return -1;
532  }
533  co_unsigned16_t type =
534  (co_unsigned16_t)strtoul(val, NULL, 0);
535 
536  // Create and insert the sub-object.
537  co_sub_t *sub = co_sub_build(obj,
538  (co_unsigned8_t)subidx, type, name);
539  if (!sub)
540  return -1;
541 
542  // Parse the configuration section for the sub-object.
543  if (co_sub_parse_cfg(sub, cfg, section) == -1)
544  return -1;
545  }
546 
547  // Create an array based on CompactSubObj.
548  if (subobj) {
549  co_sub_t *sub = co_sub_build(obj, 0,
550  CO_DEFTYPE_UNSIGNED8, "NrOfObjects");
551  if (!sub)
552  return -1;
553  co_val_make(sub->type, sub->val, &subobj,
554  sizeof(subobj));
555 #ifndef LELY_NO_CO_OBJ_DEFAULT
556  co_val_copy(sub->type, &sub->def, sub->val);
557 #endif
559 
560  name = config_get(cfg, section, "ParameterName");
561 
562  // Obtain the data type of the sub-object.
563  val = config_get(cfg, section, "DataType");
564  if (!val || !*val) {
565  diag_at(DIAG_ERROR, 0, &at,
566  "DataType not specified");
567  return -1;
568  }
569  co_unsigned16_t type =
570  (co_unsigned16_t)strtoul(val, NULL, 0);
571 
572  // Create the sub-objects.
573  for (size_t subidx = 1; subidx <= subobj; subidx++) {
574  // Create name of the sub-object.
575  char *subname = NULL;
576  // clang-format off
577  if (asprintf(&subname, "%s%u", name,
578  (co_unsigned8_t)subidx) < 0)
579  // clang-format on
580  return -1;
581 
582  // Create and insert the sub-object.
583  sub = co_sub_build(obj, (co_unsigned8_t)subidx,
584  type, subname);
585  free(subname);
586  if (!sub)
587  return -1;
588 
589  // Parse the configuration section for the
590  // sub-object.
591  if (co_sub_parse_cfg(sub, cfg, section) == -1)
592  return -1;
593  }
594 
595 #ifndef LELY_NO_CO_OBJ_NAME
596  // Parse the names of the sub-objects.
597  if (co_obj_parse_names(obj, cfg) == -1)
598  return -1;
599 #endif
600 
601  // Parse the values of the sub-objects.
602  if (co_obj_parse_values(obj, cfg) == -1)
603  return -1;
604  }
605 
606  co_sub_t *sub = co_obj_find_sub(obj, 0x00);
607  if (!sub || co_sub_get_type(sub) != CO_DEFTYPE_UNSIGNED8) {
608  diag(DIAG_ERROR, 0,
609  "object 0x%04X does not provide the highest sub-index implemented",
610  idx);
611  return -1;
612  }
613  } else {
614  // Obtain the data type of the object (optional for DOMAIN
615  // objects).
616  co_unsigned16_t type = code == CO_OBJECT_DOMAIN
618  : 0;
619  val = config_get(cfg, section, "DataType");
620  if (val && *val)
621  type = (co_unsigned16_t)strtoul(val, NULL, 0);
622  if (!type) {
623  diag_at(DIAG_ERROR, 0, &at, "DataType not specified");
624  return -1;
625  }
626 
627  // Create and insert the sub-object.
628  co_sub_t *sub = co_sub_build(obj, 0, type, name);
629  if (!sub)
630  return -1;
631 
632  // Parse the configuration section for the sub-object.
633  if (co_sub_parse_cfg(sub, cfg, section) == -1)
634  return -1;
635  }
636 
637  return 0;
638 }
639 
640 #ifndef LELY_NO_CO_OBJ_NAME
641 static int
642 co_obj_parse_names(co_obj_t *obj, const config_t *cfg)
643 {
644  assert(obj);
645  assert(cfg);
646 
647  co_unsigned16_t idx = co_obj_get_idx(obj);
648 
649  // Create the section name for the explicit names of the sub-objects.
650  char section[9];
651  snprintf(section, sizeof(section), "%XName", idx);
652 
653  const char *val = config_get(cfg, section, "NrOfEntries");
654  if (!val || !*val)
655  return 0;
656 
657  co_unsigned8_t n = (co_unsigned8_t)strtoul(val, NULL, 0);
658  for (size_t subidx = 1; n && subidx < 0xff; subidx++) {
659  char key[4];
660  snprintf(key, sizeof(key), "%u", (co_unsigned8_t)subidx);
661 
662  val = config_get(cfg, section, key);
663  if (val && *val) {
664  n--;
665  co_sub_t *sub = co_obj_find_sub(
666  obj, (co_unsigned8_t)subidx);
667  if (sub && co_sub_set_name(sub, val) == -1) {
669  "unable to set name of sub-object %Xsub%X",
670  (co_unsigned16_t)idx,
671  (co_unsigned8_t)subidx);
672  return -1;
673  }
674  }
675  }
676 
677  return 0;
678 }
679 #endif // LELY_NO_CO_OBJ_NAME
680 
681 static int
682 co_obj_parse_values(co_obj_t *obj, const config_t *cfg)
683 {
684  assert(obj);
685  assert(cfg);
686 
687  co_unsigned8_t id = co_dev_get_id(co_obj_get_dev(obj));
688  co_unsigned16_t idx = co_obj_get_idx(obj);
689 
690  // Create the section name for the explicit values of the sub-objects.
691  char section[10];
692  snprintf(section, sizeof(section), "%XValue", (co_unsigned16_t)idx);
693  struct floc at = { section, 0, 0 };
694 
695  const char *val = config_get(cfg, section, "NrOfEntries");
696  if (!val || !*val)
697  return 0;
698 
699  co_unsigned8_t n = (co_unsigned8_t)strtoul(val, NULL, 0);
700  for (size_t subidx = 1; n && subidx < 0xff; subidx++) {
701  char key[4];
702  snprintf(key, sizeof(key), "%u", (co_unsigned8_t)subidx);
703 
704  val = config_get(cfg, section, key);
705  if (val && *val) {
706  n--;
707  co_sub_t *sub = co_obj_find_sub(
708  obj, (co_unsigned8_t)subidx);
709  co_unsigned16_t type = co_sub_get_type(sub);
710  co_val_fini(type, sub->val);
711  size_t chars = co_val_lex_id(val, NULL, &at);
712  if (chars) {
713  val += chars;
715  }
716  if (!co_val_lex_dcf(type, sub->val, val, NULL, &at)) {
718  "unable to set value of sub-object %Xsub%X",
719  (co_unsigned16_t)idx,
720  (co_unsigned8_t)subidx);
721  return -1;
722  }
723  if (sub->flags & CO_OBJ_FLAGS_VAL_NODEID)
724  co_val_set_id(type, sub->val, id);
725  }
726  }
727 
728  return 0;
729 }
730 
731 static co_obj_t *
732 co_obj_build(co_dev_t *dev, co_unsigned16_t idx)
733 {
734  assert(dev);
735 
736  co_obj_t *obj = co_obj_create(idx);
737  if (!obj) {
738  diag(DIAG_ERROR, get_errc(), "unable to create object 0x%04X",
739  idx);
740  return NULL;
741  }
742 
743  if (co_dev_insert_obj(dev, obj) == -1) {
744  diag(DIAG_ERROR, 0,
745  "unable to insert object 0x%04X into the object dictionary",
746  idx);
747  co_obj_destroy(obj);
748  return NULL;
749  }
750 
751  return obj;
752 }
753 
754 static int
755 co_sub_parse_cfg(co_sub_t *sub, const config_t *cfg, const char *section)
756 {
757  assert(sub);
758  assert(cfg);
759 
760  int result = -1;
761 
762  const char *val;
763  struct floc at = { section, 0, 0 };
764 
765  co_unsigned8_t id = co_dev_get_id(co_obj_get_dev(co_sub_get_obj(sub)));
766  co_unsigned16_t type = co_sub_get_type(sub);
767 
768 #ifdef LELY_NO_CO_OBJ_DEFAULT
769  union co_val def;
770  co_val_init(type, &def);
771 #endif
772 
773 #ifndef LELY_NO_CO_OBJ_LIMITS
774  val = config_get(cfg, section, "LowLimit");
775  if (val && *val) {
776  size_t chars = co_val_lex_id(val, NULL, &at);
777  if (chars) {
778  val += chars;
780  }
781  if (!co_val_lex_dcf(type, &sub->min, val, NULL, &at)) {
782  diag_at(DIAG_ERROR, get_errc(), &at,
783  "unable to parse LowLimit");
784  goto error;
785  }
786  if (sub->flags & CO_OBJ_FLAGS_MIN_NODEID)
787  co_val_set_id(type, &sub->min, id);
788  }
789 
790  val = config_get(cfg, section, "HighLimit");
791  if (val && *val) {
792  size_t chars = co_val_lex_id(val, NULL, &at);
793  if (chars) {
794  val += chars;
796  }
797  if (!co_val_lex_dcf(type, &sub->max, val, NULL, &at)) {
798  diag_at(DIAG_ERROR, get_errc(), &at,
799  "unable to parse HighLimit");
800  goto error;
801  }
802  if (sub->flags & CO_OBJ_FLAGS_MAX_NODEID)
803  co_val_set_id(type, &sub->max, id);
804  }
805 #endif // LELY_NO_CO_OBJ_LIMITS
806 
807  unsigned int access = co_sub_get_access(sub);
808  val = config_get(cfg, section, "AccessType");
809  if (val && *val) {
810  if (!strcasecmp(val, "ro")) {
811  access = CO_ACCESS_RO;
812  } else if (!strcasecmp(val, "wo")) {
813  access = CO_ACCESS_WO;
814  } else if (!strcasecmp(val, "rw")) {
815  access = CO_ACCESS_RW;
816  } else if (!strcasecmp(val, "rwr")) {
817  access = CO_ACCESS_RWR;
818  } else if (!strcasecmp(val, "rww")) {
819  access = CO_ACCESS_RWW;
820  } else if (!strcasecmp(val, "const")) {
821  access = CO_ACCESS_CONST;
822  } else {
823  diag_at(DIAG_ERROR, 0, &at, "AccessType = %s", val);
824  goto error;
825  }
826  co_sub_set_access(sub, access);
827  } else if (type != CO_DEFTYPE_DOMAIN) {
828  diag_at(DIAG_ERROR, 0, &at, "AccessType not specified");
829  goto error;
830  }
831 
832  val = config_get(cfg, section, "DefaultValue");
833  if (val && *val) {
834  size_t chars = co_val_lex_id(val, NULL, &at);
835  if (chars) {
836  val += chars;
838  }
839 #ifdef LELY_NO_CO_OBJ_DEFAULT
840  if (!co_val_lex_dcf(type, &def, val, NULL, &at)) {
841 #else
842  if (!co_val_lex_dcf(type, &sub->def, val, NULL, &at)) {
843 #endif
844  diag_at(DIAG_ERROR, get_errc(), &at,
845  "unable to parse DefaultValue");
846  goto error;
847  }
848  if (sub->flags & CO_OBJ_FLAGS_DEF_NODEID)
849 #ifdef LELY_NO_CO_OBJ_DEFAULT
850  co_val_set_id(type, &def, id);
851 #else
852  co_val_set_id(type, &sub->def, id);
853 #endif
854  }
855 
856  val = config_get(cfg, section, "PDOMapping");
857  if (val && *val)
858  co_sub_set_pdo_mapping(sub, strtoul(val, NULL, 0));
859 
860  val = config_get(cfg, section, "ObjFlags");
861  if (val && *val)
862  sub->flags |= strtoul(val, NULL, 0);
863 
864  val = config_get(cfg, section, "ParameterValue");
865  if (val && *val) {
866  size_t chars = co_val_lex_id(val, NULL, &at);
867  if (chars) {
868  val += chars;
870  }
871  if (!co_val_lex_dcf(type, sub->val, val, NULL, &at)) {
872  diag_at(DIAG_ERROR, get_errc(), &at,
873  "unable to parse ParameterValue");
874  goto error;
875  }
876  if (sub->flags & CO_OBJ_FLAGS_VAL_NODEID)
877  co_val_set_id(type, sub->val, id);
878 #ifndef LELY_NO_CO_OBJ_FILE
879  } else if (type == CO_DEFTYPE_DOMAIN
880  && (val = config_get(cfg, section, "UploadFile"))
881  != NULL) {
882  if (!(access & CO_ACCESS_READ) || (access & CO_ACCESS_WRITE)) {
883  diag_at(DIAG_WARNING, 0, &at,
884  "AccessType must be 'ro' or 'const' when using UploadFile");
885  access |= CO_ACCESS_READ;
886  access &= ~CO_ACCESS_WRITE;
887  co_sub_set_access(sub, access);
888  }
889 
891  // Store the filename instead of its contents in the object
892  // dictionary.
893  if (co_val_init_dom(sub->val, val, strlen(val) + 1) == -1) {
894  diag_at(DIAG_ERROR, get_errc(), &at,
895  "unable to parse UploadFile");
896  goto error;
897  }
898  } else if (type == CO_DEFTYPE_DOMAIN
899  && (val = config_get(cfg, section, "DownloadFile"))
900  != NULL) {
901  if ((access & CO_ACCESS_READ) || !(access & CO_ACCESS_WRITE)) {
902  diag_at(DIAG_WARNING, 0, &at,
903  "AccessType must be 'wo' when using DownloadFile");
904  access &= ~CO_ACCESS_READ;
905  access |= CO_ACCESS_WRITE;
906  co_sub_set_access(sub, access);
907  }
909  // Store the filename instead of its contents in the object
910  // dictionary.
911  if (co_val_init_dom(sub->val, val, strlen(val) + 1) == -1) {
912  diag_at(DIAG_ERROR, get_errc(), &at,
913  "unable to parse DownloadFile");
914  goto error;
915  }
916 #endif
917  } else {
918  if (sub->flags & CO_OBJ_FLAGS_DEF_NODEID)
920 #ifdef LELY_NO_CO_OBJ_DEFAULT
921  co_val_copy(type, sub->val, &def);
922 #else
923  co_val_copy(type, sub->val, &sub->def);
924 #endif
925  }
926 
927 #ifndef LELY_NO_CO_OBJ_LIMITS
928  if (co_type_is_basic(type)) {
929  const void *min = co_sub_addressof_min(sub);
930  const void *max = co_sub_addressof_max(sub);
931 #ifndef LELY_NO_CO_OBJ_DEFAULT
932  const void *def = co_sub_addressof_def(sub);
933 #endif
934  const void *val = co_sub_addressof_val(sub);
935  if (co_val_cmp(type, min, max) > 0)
936  diag_at(DIAG_WARNING, 0, &at,
937  "LowLimit exceeds HighLimit");
938 #ifndef LELY_NO_CO_OBJ_DEFAULT
939  if (co_val_cmp(type, def, min) < 0)
940  diag_at(DIAG_WARNING, 0, &at, "DefaultValue underflow");
941  if (co_val_cmp(type, def, max) > 0)
942  diag_at(DIAG_WARNING, 0, &at, "DefaultValue overflow");
943 #endif
944  if (co_val_cmp(type, val, min) < 0)
945  diag_at(DIAG_WARNING, 0, &at,
946  "ParameterValue underflow");
947  if (co_val_cmp(type, val, max) > 0)
948  diag_at(DIAG_WARNING, 0, &at,
949  "ParameterValue overflow");
950  }
951 #endif
952 
953  result = 0;
954 
955 error:
956 #ifdef LELY_NO_CO_OBJ_DEFAULT
957  co_val_fini(type, &def);
958 #endif
959  return result;
960 }
961 
962 static co_sub_t *
963 co_sub_build(co_obj_t *obj, co_unsigned8_t subidx, co_unsigned16_t type,
964  const char *name)
965 {
966  assert(obj);
967 
968  co_unsigned16_t idx = co_obj_get_idx(obj);
969 
970  co_sub_t *sub = co_sub_create(subidx, type);
971  if (!sub) {
973  "unable to create sub-object %Xsub%X", idx,
974  subidx);
975  goto error;
976  }
977 
978  if (co_obj_insert_sub(obj, sub) == -1) {
979  diag(DIAG_ERROR, 0,
980  "unable to insert sub-object %Xsub%X into the object dictionary",
981  idx, subidx);
982  goto error;
983  }
984 
985 #ifndef LELY_NO_CO_OBJ_NAME
986  if (co_sub_set_name(sub, name) == -1) {
988  "unable to set name of sub-object %Xsub%X", idx,
989  subidx);
990  goto error;
991  }
992 #else
993  (void)name;
994 #endif
995 
996  return sub;
997 
998 error:
999  co_sub_destroy(sub);
1000  return NULL;
1001 }
1002 
1003 static int
1004 co_rpdo_build(co_dev_t *dev, co_unsigned16_t num, int mask)
1005 {
1006  assert(dev);
1007  assert(num && num <= 512);
1008 
1009  // Find the highest sub-index supported.
1010  mask &= 0x3f;
1011  co_unsigned8_t n = 0;
1012  for (int i = 0; i < 6; i++) {
1013  if (mask & (1 << i))
1014  n = i + 1;
1015  }
1016 
1017  // Create the RPDO communication parameter if it does not exist.
1018  if (!co_dev_find_obj(dev, 0x1400 + num - 1)) {
1019  co_obj_t *obj = co_obj_build(dev, 0x1400 + num - 1);
1020  if (!obj)
1021  return -1;
1022 #ifndef LELY_NO_CO_OBJ_NAME
1023  if (co_obj_set_name(obj, "RPDO communication parameter")
1024  == -1) {
1025  diag(DIAG_ERROR, get_errc(), "unable configure RPDO %u",
1026  num);
1027  return -1;
1028  }
1029 #endif
1031 
1032  co_sub_t *sub = co_sub_build(obj, 0, CO_DEFTYPE_UNSIGNED8,
1033  "Highest sub-index supported");
1034  if (!sub)
1035  return -1;
1036  co_val_make(sub->type, sub->val, &n, sizeof(n));
1037 #ifndef LELY_NO_CO_OBJ_DEFAULT
1038  co_val_copy(sub->type, &sub->def, sub->val);
1039 #endif
1041 
1042  if (mask & 0x01) {
1043  sub = co_sub_build(obj, 1, CO_DEFTYPE_UNSIGNED32,
1044  "COB-ID used by RPDO");
1045  if (!sub)
1046  return -1;
1047  co_unsigned32_t cobid = CO_PDO_COBID_VALID;
1048  if (num <= 4) {
1049  cobid = num * 0x100 + 0x100 + 0xff;
1052  }
1053  co_val_make(sub->type, sub->val, &cobid, sizeof(cobid));
1054 #ifndef LELY_NO_CO_OBJ_DEFAULT
1055  co_val_copy(sub->type, &sub->def, sub->val);
1056 #endif
1058  }
1059 
1060  if (mask & 0x02) {
1061  sub = co_sub_build(obj, 2, CO_DEFTYPE_UNSIGNED8,
1062  "Transmission type");
1063  if (!sub)
1064  return -1;
1066  }
1067 
1068  if (mask & 0x04) {
1069  sub = co_sub_build(obj, 3, CO_DEFTYPE_UNSIGNED16,
1070  "Inhibit time");
1071  if (!sub)
1072  return -1;
1074  }
1075 
1076  if (mask & 0x08) {
1077  sub = co_sub_build(obj, 4, CO_DEFTYPE_UNSIGNED8,
1078  "Compatibility entry");
1079  if (!sub)
1080  return -1;
1082  }
1083 
1084  if (mask & 0x10) {
1085  sub = co_sub_build(obj, 5, CO_DEFTYPE_UNSIGNED16,
1086  "Event timer");
1087  if (!sub)
1088  return -1;
1090  }
1091 
1092  if (mask & 0x20) {
1093  sub = co_sub_build(obj, 6, CO_DEFTYPE_UNSIGNED8,
1094  "SYNC start value");
1095  if (!sub)
1096  return -1;
1098  }
1099  }
1100 
1101  // Create the RPDO mapping parameter if it does not exist.
1102  if (!co_dev_find_obj(dev, 0x1600 + num - 1)) {
1103  co_obj_t *obj = co_obj_build(dev, 0x1600 + num - 1);
1104  if (!obj)
1105  return -1;
1106 #ifndef LELY_NO_CO_OBJ_NAME
1107  if (co_obj_set_name(obj, "RPDO mapping parameter") == -1) {
1108  diag(DIAG_ERROR, get_errc(), "unable configure RPDO %u",
1109  num);
1110  return -1;
1111  }
1112 #endif
1114 
1115  co_sub_t *sub = co_sub_build(obj, 0, CO_DEFTYPE_UNSIGNED8,
1116  "Highest sub-index supported");
1117  if (!sub)
1118  return -1;
1120 
1121  for (co_unsigned8_t i = 1; i <= 0x40; i++) {
1122  char name[22];
1123  snprintf(name, sizeof(name), "Application object %u",
1124  i);
1125 
1126  co_sub_t *sub = co_sub_build(
1127  obj, i, CO_DEFTYPE_UNSIGNED32, name);
1128  if (!sub)
1129  return -1;
1131  }
1132  }
1133 
1134  return 0;
1135 }
1136 
1137 static int
1138 co_tpdo_build(co_dev_t *dev, co_unsigned16_t num, int mask)
1139 {
1140  assert(dev);
1141  assert(num && num <= 512);
1142 
1143  // Find the highest sub-index supported.
1144  mask &= 0x3f;
1145  co_unsigned8_t n = 0;
1146  for (int i = 0; i < 6; i++) {
1147  if (mask & (1 << i))
1148  n = i + 1;
1149  }
1150 
1151  // Create the TPDO communication parameter if it does not exist.
1152  if (!co_dev_find_obj(dev, 0x1800 + num - 1)) {
1153  co_obj_t *obj = co_obj_build(dev, 0x1800 + num - 1);
1154  if (!obj)
1155  return -1;
1156 #ifndef LELY_NO_CO_OBJ_NAME
1157  if (co_obj_set_name(obj, "TPDO communication parameter")
1158  == -1) {
1159  diag(DIAG_ERROR, get_errc(), "unable configure TPDO %u",
1160  num);
1161  return -1;
1162  }
1163 #endif
1165 
1166  co_sub_t *sub = co_sub_build(obj, 0, CO_DEFTYPE_UNSIGNED8,
1167  "Highest sub-index supported");
1168  if (!sub)
1169  return -1;
1170  co_val_make(sub->type, sub->val, &n, sizeof(n));
1171 #ifndef LELY_NO_CO_OBJ_DEFAULT
1172  co_val_copy(sub->type, &sub->def, sub->val);
1173 #endif
1175 
1176  if (mask & 0x01) {
1177  sub = co_sub_build(obj, 1, CO_DEFTYPE_UNSIGNED32,
1178  "COB-ID used by TPDO");
1179  if (!sub)
1180  return -1;
1181  co_unsigned32_t cobid = CO_PDO_COBID_VALID;
1182  if (num <= 4) {
1183  cobid = num * 0x100 + 0x80 + 0xff;
1186  }
1187  co_val_make(sub->type, sub->val, &cobid, sizeof(cobid));
1188 #ifndef LELY_NO_CO_OBJ_DEFAULT
1189  co_val_copy(sub->type, &sub->def, sub->val);
1190 #endif
1192  }
1193 
1194  if (mask & 0x02) {
1195  sub = co_sub_build(obj, 2, CO_DEFTYPE_UNSIGNED8,
1196  "Transmission type");
1197  if (!sub)
1198  return -1;
1200  }
1201 
1202  if (mask & 0x04) {
1203  sub = co_sub_build(obj, 3, CO_DEFTYPE_UNSIGNED16,
1204  "Inhibit time");
1205  if (!sub)
1206  return -1;
1208  }
1209 
1210  if (mask & 0x08) {
1211  sub = co_sub_build(obj, 4, CO_DEFTYPE_UNSIGNED8,
1212  "Reserved");
1213  if (!sub)
1214  return -1;
1216  }
1217 
1218  if (mask & 0x10) {
1219  sub = co_sub_build(obj, 5, CO_DEFTYPE_UNSIGNED16,
1220  "Event timer");
1221  if (!sub)
1222  return -1;
1224  }
1225 
1226  if (mask & 0x20) {
1227  sub = co_sub_build(obj, 6, CO_DEFTYPE_UNSIGNED8,
1228  "SYNC start value");
1229  if (!sub)
1230  return -1;
1232  }
1233  }
1234 
1235  // Create the TPDO mapping parameter if it does not exist.
1236  if (!co_dev_find_obj(dev, 0x1a00 + num - 1)) {
1237  co_obj_t *obj = co_obj_build(dev, 0x1a00 + num - 1);
1238  if (!obj)
1239  return -1;
1240 #ifndef LELY_NO_CO_OBJ_NAME
1241  if (co_obj_set_name(obj, "TPDO mapping parameter") == -1) {
1242  diag(DIAG_ERROR, get_errc(), "unable configure TPDO %u",
1243  num);
1244  return -1;
1245  }
1246 #endif
1248 
1249  co_sub_t *sub = co_sub_build(obj, 0, CO_DEFTYPE_UNSIGNED8,
1250  "Highest sub-index supported");
1251  if (!sub)
1252  return -1;
1254 
1255  for (co_unsigned8_t i = 1; i <= 0x40; i++) {
1256  char name[22];
1257  snprintf(name, sizeof(name), "Application object %u",
1258  i);
1259 
1260  co_sub_t *sub = co_sub_build(
1261  obj, i, CO_DEFTYPE_UNSIGNED32, name);
1262  if (!sub)
1263  return -1;
1265  }
1266  }
1267 
1268  return 0;
1269 }
1270 
1271 size_t
1272 co_val_lex_dcf(co_unsigned16_t type, void *val, const char *begin,
1273  const char *end, struct floc *at)
1274 {
1275  assert(begin);
1276  assert(!end || end >= begin);
1277 
1278  switch (type) {
1279  case CO_DEFTYPE_OCTET_STRING: {
1280  size_t n = 0;
1281  size_t chars = lex_hex(begin, end, NULL, NULL, &n);
1282  if (val) {
1283  if (co_val_init_os(val, NULL, n) == -1) {
1284  diag_if(DIAG_ERROR, get_errc(), at,
1285  "unable to create value of type OCTET_STRING");
1286  return 0;
1287  }
1288  uint_least8_t *os = *(void **)val;
1289  assert(!n || os);
1290  lex_hex(begin, end, NULL, os, &n);
1291  }
1292  return floc_lex(at, begin, begin + chars);
1293  }
1295  const char *cp;
1296  // Count the number of 16-bit code units.
1297  size_t n = 0;
1298  for (cp = begin; (!end || cp < end) && *cp;) {
1299  char32_t c32 = 0;
1300  cp += lex_utf8(cp, end, NULL, &c32);
1301  assert(c32 < 0xd800 || c32 > 0xdfff);
1302  n += c32 <= 0xffff ? 1 : 2;
1303  }
1304  if (val) {
1305  if (co_val_init_us_n(val, NULL, n) == -1) {
1306  diag_if(DIAG_ERROR, get_errc(), at,
1307  "unable to create value of type UNICODE_STRING");
1308  return 0;
1309  }
1310  // Parse the UTF-8 characters.
1311  char16_t *us = *(void **)val;
1312  assert(us);
1313  for (cp = begin; (!end || cp < end) && *cp;) {
1314  char32_t c32 = 0;
1315  cp += lex_utf8(cp, end, NULL, &c32);
1316  assert(c32 < 0xd800 || c32 > 0xdfff);
1317  // Store the character as UTF-16LE.
1318  if (c32 <= 0xffff) {
1319  *us++ = c32;
1320  } else {
1321  c32 -= 0x10000ul;
1322  *us++ = 0xd800 + ((c32 >> 10) & 0x3ff);
1323  *us++ = 0xdc00 + (c32 & 0x3ff);
1324  }
1325  }
1326  }
1327  return floc_lex(at, begin, cp);
1328  }
1329  case CO_DEFTYPE_DOMAIN: {
1330  size_t n = 0;
1331  size_t chars = lex_hex(begin, end, NULL, NULL, &n);
1332  if (val) {
1333  if (co_val_init_dom(val, NULL, n) == -1) {
1334  diag_if(DIAG_ERROR, get_errc(), at,
1335  "unable to create value of type DOMAIN");
1336  return 0;
1337  }
1338  void *dom = *(void **)val;
1339  assert(!n || dom);
1340  lex_hex(begin, end, NULL, dom, &n);
1341  }
1342  return floc_lex(at, begin, begin + chars);
1343  }
1344  default: return co_val_lex(type, val, begin, end, at);
1345  }
1346 }
1347 
1348 static size_t
1349 co_val_lex_id(const char *begin, const char *end, struct floc *at)
1350 {
1351  assert(begin);
1352 
1353  const char *cp = begin;
1354 
1355  if ((end && cp - end < 7) || strncasecmp(begin, "$NODEID", 7))
1356  return 0;
1357  cp += 7;
1358  if (at)
1359  at->column += 7;
1360 
1361  cp += lex_ctype(isspace, cp, end, at);
1362  cp += lex_char('+', cp, end, at);
1363  cp += lex_ctype(isspace, cp, end, at);
1364 
1365  return cp - begin;
1366 }
1367 
1368 static void
1369 co_val_set_id(co_unsigned16_t type, void *val, co_unsigned8_t id)
1370 {
1371  assert(val);
1372 
1373  union co_val *u = val;
1374  switch (type) {
1375 #define LELY_CO_DEFINE_TYPE(a, b, c, d) \
1376  case CO_DEFTYPE_##a: \
1377  u->c += id; \
1378  break;
1379 #include <lely/co/def/basic.def>
1380 #undef LELY_CO_DEFINE_TYPE
1381  }
1382 }
1383 
1384 static co_unsigned16_t
1385 config_get_idx(const config_t *cfg, const char *section, co_unsigned16_t maxidx,
1386  co_unsigned16_t *idx)
1387 {
1388  assert(cfg);
1389 
1390  if (!idx)
1391  maxidx = 0;
1392 
1393  const char *val = config_get(cfg, section, "SupportedObjects");
1394  if (!val || !*val)
1395  return 0;
1396 
1397  co_unsigned16_t n = (co_unsigned16_t)strtoul(val, NULL, 0);
1398  for (size_t i = 0; i < (size_t)MIN(n, maxidx); i++) {
1399  char key[6];
1400  snprintf(key, sizeof(key), "%u", (co_unsigned16_t)(i + 1));
1401 
1402  val = config_get(cfg, section, key);
1403  // clang-format off
1404  idx[i] = val && *val
1405  ? (co_unsigned16_t)strtoul(val, NULL, 0) : 0;
1406  // clang-format on
1407  }
1408 
1409  return n;
1410 }
1411 
1412 #endif // !LELY_NO_CO_DCF
CO_PDO_COBID_VALID
#define CO_PDO_COBID_VALID
The bit in the PDO COB-ID specifying whether the PDO exists and is valid.
Definition: pdo.h:28
co_obj_set_name
int co_obj_set_name(co_obj_t *obj, const char *name)
Sets the name of a CANopen object.
Definition: obj.c:262
CO_OBJ_FLAGS_MAX_NODEID
#define CO_OBJ_FLAGS_MAX_NODEID
The upper limit of the object value is of the form $NODEID { "+" number }.
Definition: obj.h:108
CO_BAUD_20
#define CO_BAUD_20
A bit rate of 20 kbit/s.
Definition: dev.h:77
CO_ACCESS_RW
#define CO_ACCESS_RW
Read or write access.
Definition: obj.h:75
co_val_copy
size_t co_val_copy(co_unsigned16_t type, void *dst, const void *src)
Copies one value to another.
Definition: val.c:344
CO_OBJ_FLAGS_DOWNLOAD_FILE
#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
diag_at
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_BAUD_50
#define CO_BAUD_50
A bit rate of 50 kbit/s.
Definition: dev.h:74
__co_sub::def
union co_val def
The default value.
Definition: obj.h:75
lex_ctype
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:51
co_val_fini
void co_val_fini(co_unsigned16_t type, void *val)
Finalizes a value of the specified data type.
Definition: val.c:275
CO_DEFTYPE_UNSIGNED32
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50
CO_ACCESS_RWW
#define CO_ACCESS_RWW
Read or write on process output.
Definition: obj.h:81
__co_sub::val
void * val
A pointer to the sub-object value.
Definition: obj.h:78
string.h
CO_DEFTYPE_UNSIGNED16
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition: type.h:47
lex_hex
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:652
diag.h
co_obj_set_code
int co_obj_set_code(co_obj_t *obj, co_unsigned8_t code)
Sets the code (type) of a CANopen object.
Definition: obj.c:294
__co_dev::baud
unsigned baud
The supported bit rates.
Definition: dev.c:63
MIN
#define MIN(a, b)
Returns the minimum of a and b.
Definition: util.h:57
co_obj_get_idx
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition: obj.c:154
__co_sub::type
co_unsigned16_t type
The data type.
Definition: obj.h:62
co_obj_get_dev
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:146
co_dev_set_rate
void co_dev_set_rate(co_dev_t *dev, co_unsigned16_t rate)
Sets the (pending) baudrate of a CANopen device.
Definition: dev.c:516
co_type_is_basic
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
__co_sub::max
union co_val max
The upper limit of the object value.
Definition: obj.h:71
__config
A configuration struct.
Definition: config.c:35
co_dev_get_id
co_unsigned8_t co_dev_get_id(const co_dev_t *dev)
Returns the node-ID of a CANopen device.
Definition: dev.c:207
get_errc
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_create_from_dcf_text
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
co_sub_addressof_val
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:667
errno2c
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
CO_BAUD_125
#define CO_BAUD_125
A bit rate of 125 kbit/s.
Definition: dev.h:71
lex.h
CO_DEFTYPE_UNSIGNED8
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition: type.h:44
CO_DEFTYPE_DOMAIN
#define CO_DEFTYPE_DOMAIN
The data type (and object index) of an arbitrary large block of data.
Definition: type.h:77
co_dev_set_product_code
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:438
co.h
co_dev_set_lss
void co_dev_set_lss(co_dev_t *dev, int lss)
Sets the LSS support flag.
Definition: dev.c:532
floc
A location in a text file.
Definition: diag.h:31
co_obj_find_sub
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:225
CO_OBJECT_DOMAIN
#define CO_OBJECT_DOMAIN
A large variable amount of data.
Definition: obj.h:33
CO_DEFTYPE_OCTET_STRING
#define CO_DEFTYPE_OCTET_STRING
The data type (and object index) of an array of octets.
Definition: type.h:59
CO_BAUD_10
#define CO_BAUD_10
A bit rate of 10 kbit/s.
Definition: dev.h:80
floc_lex
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:54
__co_sub::min
union co_val min
The lower limit of the object value.
Definition: obj.h:69
co_obj_create
co_obj_t * co_obj_create(co_unsigned16_t idx)
Creates a CANopen object.
Definition: obj.c:106
CO_ACCESS_READ
#define CO_ACCESS_READ
The object can be read.
Definition: obj.h:57
DIAG_ERROR
@ DIAG_ERROR
An error.
Definition: diag.h:49
CO_ACCESS_RWR
#define CO_ACCESS_RWR
Read or write on process input.
Definition: obj.h:78
co_sub_destroy
void co_sub_destroy(co_sub_t *sub)
Destroys a CANopen sub-object.
Definition: obj.c:493
CO_OBJ_FLAGS_MIN_NODEID
#define CO_OBJ_FLAGS_MIN_NODEID
The lower limit of the object value is of the form $NODEID { "+" number }.
Definition: obj.h:105
floc::column
int column
The column number (starting from 1).
Definition: diag.h:37
co_sub_set_name
int co_sub_set_name(co_sub_t *sub, const char *name)
Sets the name of a CANopen sub-object.
Definition: obj.c:546
set_errc
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
config_parse_ini_text
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
lex_utf8
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:83
DIAG_WARNING
@ DIAG_WARNING
A warning.
Definition: diag.h:47
co_sub_addressof_def
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:638
config_parse_ini_file
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
co_sub_addressof_min
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:580
CO_BAUD_250
#define CO_BAUD_250
A bit rate of 250 kbit/s.
Definition: dev.h:68
config_create
config_t * config_create(int flags)
Creates a new configuration struct with an unnamed empty root section.
Definition: config.c:110
stdio.h
co_val_make
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:308
CO_OBJECT_ARRAY
#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
co_dev_set_order_code
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:470
strings.h
co_dev_set_revision
void co_dev_set_revision(co_dev_t *dev, co_unsigned32_t revision)
Sets the revision number of a CANopen device.
Definition: dev.c:454
co_sub_get_access
unsigned int co_sub_get_access(const co_sub_t *sub)
Returns the access type of a CANopen sub-object.
Definition: obj.c:745
co_dev_set_vendor_name
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:362
CO_OBJECT_DEFSTRUCT
#define CO_OBJECT_DEFSTRUCT
A record type definition.
Definition: obj.h:39
co_dev_create_from_dcf_file
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::name
char * name
A pointer to the name of the device.
Definition: dev.c:49
co_val_init_os
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:205
config_destroy
void config_destroy(config_t *config)
Destroys a configuration struct.
Definition: config.c:135
obj.h
co_val_cmp
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:397
co_val
A union of the CANopen static data types.
Definition: val.h:163
diag
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
co_sub_set_pdo_mapping
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:777
co_dev_set_baud
void co_dev_set_baud(co_dev_t *dev, unsigned int baud)
Sets the supported bit rates of a CANopen device.
Definition: dev.c:500
co_val_lex
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:871
__co_obj
A CANopen object.
Definition: obj.h:32
co_dev_set_product_name
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:408
__co_dev
A CANopen device.
Definition: dev.c:41
co_val_init_dom
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:256
co_sub_get_obj
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:520
CO_BAUD_1000
#define CO_BAUD_1000
A bit rate of 1 Mbit/s.
Definition: dev.h:59
co_val_init
int co_val_init(co_unsigned16_t type, void *val)
Initializes a value of the specified data type to zero.
Definition: val.c:122
CO_OBJECT_RECORD
#define CO_OBJECT_RECORD
A multiple data field object where the data fields may be any combination of simple variables.
Definition: obj.h:54
CO_DEFTYPE_UNICODE_STRING
#define CO_DEFTYPE_UNICODE_STRING
The data type (and object index) of an array of (16-bit) Unicode characters.
Definition: type.h:62
pdo.h
CO_ACCESS_WRITE
#define CO_ACCESS_WRITE
The object can be written.
Definition: obj.h:60
asprintf
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
CO_ACCESS_WO
#define CO_ACCESS_WO
Write-only access.
Definition: obj.h:72
co_sub_set_access
int co_sub_set_access(co_sub_t *sub, unsigned int access)
Sets the access type of a CANopen sub-object.
Definition: obj.c:753
CO_ACCESS_CONST
#define CO_ACCESS_CONST
Constant value.
Definition: obj.h:84
config.h
co_obj_get_code
co_unsigned8_t co_obj_get_code(const co_obj_t *obj)
Returns the object code of a CANopen object.
Definition: obj.c:286
diag_if
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:190
co_dev_set_vendor_id
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:392
CO_OBJ_FLAGS_DEF_NODEID
#define CO_OBJ_FLAGS_DEF_NODEID
The default object value is of the form $NODEID { "+" number }.
Definition: obj.h:111
co_dev_set_name
int co_dev_set_name(co_dev_t *dev, const char *name)
Sets the name of a CANopen device.
Definition: dev.c:332
co_dev_set_netid
int co_dev_set_netid(co_dev_t *dev, co_unsigned8_t id)
Sets the network-ID of a CANopen device.
Definition: dev.c:192
CONFIG_CASE
@ CONFIG_CASE
Section and key names are case-insensitive.
Definition: config.h:37
co_sub_create
co_sub_t * co_sub_create(co_unsigned8_t subidx, co_unsigned16_t type)
Creates a CANopen sub-object.
Definition: obj.c:468
__co_dev::dummy
co_unsigned32_t dummy
The data types supported for mapping dummy entries in PDOs.
Definition: dev.c:69
CO_BAUD_500
#define CO_BAUD_500
A bit rate of 500 kbit/s.
Definition: dev.h:65
stdlib.h
co_dev_set_dummy
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:548
__co_sub
A CANopen sub-object.
Definition: obj.h:54
dcf.h
co_sub_addressof_max
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:607
CO_OBJ_FLAGS_UPLOAD_FILE
#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
co_sub_get_type
co_unsigned16_t co_sub_get_type(const co_sub_t *sub)
Returns the data type of a CANopen sub-object.
Definition: obj.c:570
co_dev_set_id
int co_dev_set_id(co_dev_t *dev, co_unsigned8_t id)
Sets the node-ID of a CANopen device.
Definition: dev.c:215
CO_ACCESS_RO
#define CO_ACCESS_RO
Read-only access.
Definition: obj.h:69
co_dev_insert_obj
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:252
co_val_init_us_n
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:237
CO_OBJ_FLAGS_VAL_NODEID
#define CO_OBJ_FLAGS_VAL_NODEID
The current object value is of the form $NODEID { "+" number }.
Definition: obj.h:114
co_obj_destroy
void co_obj_destroy(co_obj_t *obj)
Destroys a CANopen object, including its sub-objects.
Definition: obj.c:118
CO_BAUD_800
#define CO_BAUD_800
A bit rate of 800 kbit/s.
Definition: dev.h:62
lex_char
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:38
__co_sub::flags
unsigned long flags
The object flags.
Definition: obj.h:84
co_obj_insert_sub
int co_obj_insert_sub(co_obj_t *obj, co_sub_t *sub)
Inserts a sub-object into a CANopen object.
Definition: obj.c:182
config_get
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
co_dev_find_obj
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:288