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
42static struct __co_dev *__co_dev_init_from_dcf_cfg(
43 struct __co_dev *dev, const config_t *cfg);
44
45static int co_dev_parse_cfg(co_dev_t *dev, const config_t *cfg);
46
47static int co_obj_parse_cfg(
48 co_obj_t *obj, const config_t *cfg, const char *section);
49#if !LELY_NO_CO_OBJ_NAME
50static int co_obj_parse_names(co_obj_t *obj, const config_t *cfg);
51#endif
52static int co_obj_parse_values(co_obj_t *obj, const config_t *cfg);
53static co_obj_t *co_obj_build(co_dev_t *dev, co_unsigned16_t idx);
54
55static int co_sub_parse_cfg(
56 co_sub_t *sub, const config_t *cfg, const char *section);
57static co_sub_t *co_sub_build(co_obj_t *obj, co_unsigned8_t subidx,
58 co_unsigned16_t type, const char *name);
59
60static int co_rpdo_build(co_dev_t *dev, co_unsigned16_t num, int mask);
61static int co_tpdo_build(co_dev_t *dev, co_unsigned16_t num, int mask);
62
63size_t co_val_lex_dcf(co_unsigned16_t type, void *val, const char *begin,
64 const char *end, struct floc *at);
65static size_t co_val_lex_id(
66 const char *begin, const char *end, struct floc *at);
67static void co_val_set_id(co_unsigned16_t type, void *val, co_unsigned8_t id);
68
69static co_unsigned16_t config_get_idx(const config_t *cfg, const char *section,
70 co_unsigned16_t maxidx, co_unsigned16_t *idx);
71
72struct __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
92error_init_dev:
93error_parse_ini_file:
94 config_destroy(cfg);
95error_create_cfg:
96 return NULL;
97}
98
100co_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
117error_init_dev:
118 __co_dev_free(dev);
119error_alloc_dev:
120 set_errc(errc);
121 return NULL;
122}
123
124struct __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
145error_init_dev:
146error_parse_ini_text:
147 config_destroy(cfg);
148error_create_cfg:
149 return NULL;
150}
151
152co_dev_t *
153co_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
170error_init_dev:
171 __co_dev_free(dev);
172error_alloc_dev:
173 set_errc(errc);
174 return NULL;
175}
176
177static 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
194error_parse_cfg:
195 __co_dev_fini(dev);
196error_init_dev:
197 return NULL;
198}
199
200static int
201co_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
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
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))
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 }
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
435error_parse_pdo:
436error_parse_dcf:
437error_parse_obj:
438 free(idx);
439error_parse_idx:
440error_parse_dev:
441 return -1;
442}
443
444static int
445co_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)
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
643static int
644co_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--;
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
683static int
684co_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--;
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 }
726 co_val_set_id(type, sub->val, id);
727 }
728 }
729
730 return 0;
731}
732
733static co_obj_t *
734co_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
756static int
757co_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)) {
785 "unable to parse LowLimit");
786 goto error;
787 }
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)) {
801 "unable to parse HighLimit");
802 goto error;
803 }
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
847 "unable to parse DefaultValue");
848 goto error;
849 }
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)) {
876 "unable to parse ParameterValue");
877 goto error;
878 }
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) {
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) {
916 "unable to parse DownloadFile");
917 goto error;
918 }
919#endif
920 } else {
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
958error:
959#if LELY_NO_CO_OBJ_DEFAULT
960 co_val_fini(type, &def);
961#endif
962 return result;
963}
964
965static co_sub_t *
966co_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
1001error:
1002 co_sub_destroy(sub);
1003 return NULL;
1004}
1005
1006static int
1007co_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
1140static int
1141co_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
1274size_t
1275co_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) {
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) {
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) {
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) {
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
1351static size_t
1352co_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
1371static void
1372co_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
1387static co_unsigned16_t
1388config_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_obj_t * co_dev_find_obj(const co_dev_t *dev, co_unsigned16_t idx)
Finds an object in the object dictionary of a CANopen device.
Definition: dev.c:279
co_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
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.
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_t * config_create(int flags)
Creates a new configuration struct with an unnamed empty root section.
Definition: config.c:115
@ CONFIG_CASE
Section and key names are case-insensitive.
Definition: config.h:37
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
void config_destroy(config_t *config)
Destroys a configuration struct.
Definition: config.c:140
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_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
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
#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
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
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
#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
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
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_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
#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
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_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
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
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_obj_create(co_unsigned16_t idx)
Creates a CANopen object.
Definition: obj.c:114
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
#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
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
#define CO_ACCESS_RWW
Read or write on process output.
Definition: obj.h:81
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_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