Lely core libraries 2.3.4
rpdo.c
Go to the documentation of this file.
1
24#include "co.h"
25
26#if !LELY_NO_CO_RPDO
27
28#include <lely/co/dev.h>
29#include <lely/co/obj.h>
30#include <lely/co/rpdo.h>
31#include <lely/co/sdo.h>
32#include <lely/co/val.h>
33#include <lely/util/errnum.h>
34#include <lely/util/time.h>
35
36#include <assert.h>
37#if !LELY_NO_STDIO
38#include <inttypes.h>
39#endif
40#include <stdlib.h>
41#include <string.h>
42
80
86static void co_rpdo_init_recv(co_rpdo_t *pdo);
87
92static void co_rpdo_init_timer_event(co_rpdo_t *pdo);
93
99static void co_rpdo_init_timer_swnd(co_rpdo_t *pdo);
100
107static co_unsigned32_t co_1400_dn_ind(
108 co_sub_t *sub, struct co_sdo_req *req, void *data);
109
116static co_unsigned32_t co_1600_dn_ind(
117 co_sub_t *sub, struct co_sdo_req *req, void *data);
118
124static int co_rpdo_recv(const struct can_msg *msg, void *data);
125
132static int co_rpdo_timer_event(const struct timespec *tp, void *data);
133
140static int co_rpdo_timer_swnd(const struct timespec *tp, void *data);
141
151static co_unsigned32_t co_rpdo_read_frame(
152 co_rpdo_t *pdo, const struct can_msg *msg);
153
154void *
155__co_rpdo_alloc(void)
156{
157 void *ptr = malloc(sizeof(struct __co_rpdo));
158#if !LELY_NO_ERRNO
159 if (!ptr)
160 set_errc(errno2c(errno));
161#endif
162 return ptr;
163}
164
165void
166__co_rpdo_free(void *ptr)
167{
168 free(ptr);
169}
170
171struct __co_rpdo *
172__co_rpdo_init(struct __co_rpdo *pdo, can_net_t *net, co_dev_t *dev,
173 co_unsigned16_t num)
174{
175 assert(pdo);
176 assert(net);
177 assert(dev);
178
179 int errc = 0;
180
181 if (!num || num > CO_NUM_PDOS) {
182 errc = errnum2c(ERRNUM_INVAL);
183 goto error_param;
184 }
185
186 // Find the PDO parameters in the object dictionary.
187 co_obj_t *obj_1400 = co_dev_find_obj(dev, 0x1400 + num - 1);
188 co_obj_t *obj_1600 = co_dev_find_obj(dev, 0x1600 + num - 1);
189 if (!obj_1400 || !obj_1600) {
190 errc = errnum2c(ERRNUM_INVAL);
191 goto error_param;
192 }
193
194 pdo->net = net;
195 pdo->dev = dev;
196 pdo->num = num;
197
198 pdo->stopped = 1;
199
200 memset(&pdo->comm, 0, sizeof(pdo->comm));
201 memset(&pdo->map, 0, sizeof(pdo->map));
202
203 pdo->recv = can_recv_create();
204 if (!pdo->recv) {
205 errc = get_errc();
206 goto error_create_recv;
207 }
209
211 if (!pdo->timer_event) {
212 errc = get_errc();
213 goto error_create_timer_event;
214 }
216
218 if (!pdo->timer_swnd) {
219 errc = get_errc();
220 goto error_create_timer_swnd;
221 }
223
224 pdo->sync = 0;
225 pdo->swnd = 0;
226 pdo->msg = (struct can_msg)CAN_MSG_INIT;
227
228 co_sdo_req_init(&pdo->req);
229
230 pdo->ind = NULL;
231 pdo->ind_data = NULL;
232 pdo->err = NULL;
233 pdo->err_data = NULL;
234
235 if (co_rpdo_start(pdo) == -1) {
236 errc = get_errc();
237 goto error_start;
238 }
239
240 return pdo;
241
242 // co_rpdo_stop(pdo);
243error_start:
245error_create_timer_swnd:
247error_create_timer_event:
249error_create_recv:
250error_param:
251 set_errc(errc);
252 return NULL;
253}
254
255void
256__co_rpdo_fini(struct __co_rpdo *pdo)
257{
258 assert(pdo);
259 assert(pdo->num >= 1 && pdo->num <= CO_NUM_PDOS);
260
261 co_rpdo_stop(pdo);
262
263 co_sdo_req_fini(&pdo->req);
264
268}
269
270co_rpdo_t *
271co_rpdo_create(can_net_t *net, co_dev_t *dev, co_unsigned16_t num)
272{
273 trace("creating Receive-PDO %d", num);
274
275 int errc = 0;
276
277 co_rpdo_t *pdo = __co_rpdo_alloc();
278 if (!pdo) {
279 errc = get_errc();
280 goto error_alloc_pdo;
281 }
282
283 if (!__co_rpdo_init(pdo, net, dev, num)) {
284 errc = get_errc();
285 goto error_init_pdo;
286 }
287
288 return pdo;
289
290error_init_pdo:
291 __co_rpdo_free(pdo);
292error_alloc_pdo:
293 set_errc(errc);
294 return NULL;
295}
296
297void
299{
300 if (rpdo) {
301 trace("destroying Receive-PDO %d", rpdo->num);
302 __co_rpdo_fini(rpdo);
303 __co_rpdo_free(rpdo);
304 }
305}
306
307int
309{
310 assert(pdo);
311
312 if (!pdo->stopped)
313 return 0;
314
315 co_unsigned16_t idx_1400 = 0x1400 + pdo->num - 1;
316 co_obj_t *obj_1400 = co_dev_find_obj(pdo->dev, idx_1400);
317 assert(obj_1400);
318 // Copy the PDO communication parameters.
319 memset(&pdo->comm, 0, sizeof(pdo->comm));
320 pdo->comm.n = co_dev_get_val_u8(pdo->dev, idx_1400, 0);
321 pdo->comm.cobid = co_dev_get_val_u32(pdo->dev, idx_1400, 1);
322 pdo->comm.trans = co_dev_get_val_u8(pdo->dev, idx_1400, 2);
323 pdo->comm.inhibit = co_dev_get_val_u16(pdo->dev, idx_1400, 3);
324 pdo->comm.event = co_dev_get_val_u16(pdo->dev, idx_1400, 5);
325 pdo->comm.sync = co_dev_get_val_u8(pdo->dev, idx_1400, 6);
326 // Set the download indication functions PDO communication parameter
327 // record.
328 co_obj_set_dn_ind(obj_1400, &co_1400_dn_ind, pdo);
329
330 co_unsigned16_t idx_1600 = 0x1600 + pdo->num - 1;
331 co_obj_t *obj_1600 = co_dev_find_obj(pdo->dev, idx_1600);
332 assert(obj_1600);
333 // Copy the PDO mapping parameter record.
334 memset(&pdo->map, 0, sizeof(pdo->map));
335 pdo->map.n = co_dev_get_val_u8(pdo->dev, idx_1600, 0);
336 for (co_sub_t *sub = co_obj_first_sub(obj_1600); sub;
337 sub = co_sub_next(sub)) {
338 co_unsigned8_t subidx = co_sub_get_subidx(sub);
339 if (subidx > 0 && subidx <= CO_PDO_NUM_MAPS)
340 pdo->map.map[subidx - 1] = co_sub_get_val_u32(sub);
341 }
342 // Set the download indication functions PDO mapping parameter record.
343 co_obj_set_dn_ind(obj_1600, &co_1600_dn_ind, pdo);
344
345 pdo->sync = 0;
346 pdo->swnd = 0;
347
349
350 pdo->stopped = 0;
351
352 return 0;
353}
354
355void
357{
358 assert(pdo);
359
360 if (pdo->stopped)
361 return;
362
365
366 can_recv_stop(pdo->recv);
367
368 // Remove the download indication functions PDO mapping parameter
369 // record.
370 co_obj_t *obj_1600 = co_dev_find_obj(pdo->dev, 0x1600 + pdo->num - 1);
371 assert(obj_1600);
372 co_obj_set_dn_ind(obj_1600, NULL, NULL);
373
374 // Remove the download indication functions PDO communication parameter
375 // record.
376 co_obj_t *obj_1400 = co_dev_find_obj(pdo->dev, 0x1400 + pdo->num - 1);
377 assert(obj_1400);
378 co_obj_set_dn_ind(obj_1400, NULL, NULL);
379
380 pdo->stopped = 1;
381}
382
383int
385{
386 assert(pdo);
387
388 return pdo->stopped;
389}
390
391can_net_t *
393{
394 assert(pdo);
395
396 return pdo->net;
397}
398
399co_dev_t *
401{
402 assert(pdo);
403
404 return pdo->dev;
405}
406
407co_unsigned16_t
409{
410 assert(pdo);
411
412 return pdo->num;
413}
414
415const struct co_pdo_comm_par *
417{
418 assert(pdo);
419
420 return &pdo->comm;
421}
422
423const struct co_pdo_map_par *
425{
426 assert(pdo);
427
428 return &pdo->map;
429}
430
431void
432co_rpdo_get_ind(const co_rpdo_t *pdo, co_rpdo_ind_t **pind, void **pdata)
433{
434 assert(pdo);
435
436 if (pind)
437 *pind = pdo->ind;
438 if (pdata)
439 *pdata = pdo->ind_data;
440}
441
442void
444{
445 assert(pdo);
446
447 pdo->ind = ind;
448 pdo->ind_data = data;
449}
450
451void
452co_rpdo_get_err(const co_rpdo_t *pdo, co_rpdo_err_t **perr, void **pdata)
453{
454 assert(pdo);
455
456 if (perr)
457 *perr = pdo->err;
458 if (pdata)
459 *pdata = pdo->err_data;
460}
461
462void
464{
465 assert(pdo);
466
467 pdo->err = err;
468 pdo->err_data = data;
469}
470
471int
473{
474 assert(pdo);
475
476 // Check whether the PDO exists and is valid.
477 if (pdo->comm.cobid & CO_PDO_COBID_VALID)
478 return 0;
479
480 struct can_msg msg = CAN_MSG_INIT;
481 msg.id = pdo->comm.cobid;
482 if (pdo->comm.cobid & CO_PDO_COBID_FRAME) {
483 msg.id &= CAN_MASK_EID;
484 msg.flags |= CAN_FLAG_IDE;
485 } else {
486 msg.id &= CAN_MASK_BID;
487 }
488 msg.flags |= CAN_FLAG_RTR;
489 return can_net_send(pdo->net, &msg);
490}
491
492int
493co_rpdo_sync(co_rpdo_t *pdo, co_unsigned8_t cnt)
494{
495 assert(pdo);
496
497 if (cnt > 240) {
499 return -1;
500 }
501
502 // Ignore SYNC objects if the transmission type is not synchronous.
503 if (pdo->comm.trans > 0xf0)
504 return 0;
505
506 // Reset the time window for synchronous PDOs.
507 pdo->swnd = 0;
509
510 // Check if we have a CAN frame waiting for a SYNC object.
511 if (!pdo->sync)
512 return 0;
513 pdo->sync = 0;
514
515 return co_rpdo_read_frame(pdo, &pdo->msg) ? -1 : 0;
516}
517
518static void
520{
521 assert(pdo);
522
523 if (!(pdo->comm.cobid & CO_PDO_COBID_VALID)) {
524 // Register the receiver under the specified CAN-ID.
525 uint_least32_t id = pdo->comm.cobid;
526 uint_least8_t flags = 0;
527 if (id & CO_PDO_COBID_FRAME) {
528 id &= CAN_MASK_EID;
530 } else {
531 id &= CAN_MASK_BID;
532 }
533 can_recv_start(pdo->recv, pdo->net, id, flags);
534 } else {
535 // Stop the receiver unless the RPDO is valid.
536 can_recv_stop(pdo->recv);
537 }
538}
539
540static void
542{
543 assert(pdo);
544
546 if (!(pdo->comm.cobid & CO_PDO_COBID_VALID) && pdo->comm.event)
547 can_timer_timeout(pdo->timer_event, pdo->net, pdo->comm.event);
548}
549
550static void
552{
553 assert(pdo);
554
556 // Ignore the synchronous window length unless the RPDO is valid and
557 // synchronous.
558 co_unsigned32_t swnd = co_dev_get_val_u32(pdo->dev, 0x1007, 0x00);
559 if (!(pdo->comm.cobid & CO_PDO_COBID_VALID) && pdo->comm.trans <= 0xf0
560 && swnd) {
561 struct timespec start = { 0, 0 };
562 can_net_get_time(pdo->net, &start);
563 timespec_add_usec(&start, swnd);
564 can_timer_start(pdo->timer_swnd, pdo->net, &start, NULL);
565 }
566}
567
568static co_unsigned32_t
569co_1400_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
570{
571 assert(sub);
572 assert(req);
573 co_rpdo_t *pdo = data;
574 assert(pdo);
575 assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1400 + pdo->num - 1);
576
577 co_unsigned16_t type = co_sub_get_type(sub);
578 assert(!co_type_is_array(type));
579
580 union co_val val;
581 co_unsigned32_t ac = 0;
582 if (co_sdo_req_dn_val(req, type, &val, &ac) == -1)
583 return ac;
584
585 switch (co_sub_get_subidx(sub)) {
586 case 0: return CO_SDO_AC_NO_WRITE;
587 case 1: {
588 assert(type == CO_DEFTYPE_UNSIGNED32);
589 co_unsigned32_t cobid = val.u32;
590 co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
591 if (cobid == cobid_old)
592 return 0;
593
594 // The CAN-ID cannot be changed when the PDO is and remains
595 // valid.
596 int valid = !(cobid & CO_PDO_COBID_VALID);
597 int valid_old = !(cobid_old & CO_PDO_COBID_VALID);
598 uint_least32_t canid = cobid & CAN_MASK_EID;
599 uint_least32_t canid_old = cobid_old & CAN_MASK_EID;
600 if (valid && valid_old && canid != canid_old)
601 return CO_SDO_AC_PARAM_VAL;
602
603 // A 29-bit CAN-ID is only valid if the frame bit is set.
604 if (!(cobid & CO_PDO_COBID_FRAME)
605 && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))
606 return CO_SDO_AC_PARAM_VAL;
607
608 pdo->comm.cobid = cobid;
609
610 pdo->sync = 0;
611 pdo->swnd = 0;
612
615 break;
616 }
617 case 2: {
618 assert(type == CO_DEFTYPE_UNSIGNED8);
619 co_unsigned8_t trans = val.u8;
620 co_unsigned8_t trans_old = co_sub_get_val_u8(sub);
621 if (trans == trans_old)
622 return 0;
623
624 // Transmission types 0xF1..0xFD are reserved.
625 if (trans > 0xf0 && trans < 0xfe)
626 return CO_SDO_AC_PARAM_VAL;
627
628 pdo->comm.trans = trans;
629
630 break;
631 }
632 case 3: {
633 assert(type == CO_DEFTYPE_UNSIGNED16);
634 co_unsigned16_t inhibit = val.u16;
635 co_unsigned16_t inhibit_old = co_sub_get_val_u16(sub);
636 if (inhibit == inhibit_old)
637 return 0;
638
639 // The inhibit time cannot be changed while the PDO exists and
640 // is valid.
641 if (!(pdo->comm.cobid & CO_PDO_COBID_VALID))
642 return CO_SDO_AC_PARAM_VAL;
643
644 pdo->comm.inhibit = inhibit;
645 break;
646 }
647 case 5: {
648 assert(type == CO_DEFTYPE_UNSIGNED16);
649 co_unsigned16_t event = val.u16;
650 co_unsigned16_t event_old = co_sub_get_val_u16(sub);
651 if (event == event_old)
652 return 0;
653
654 pdo->comm.event = event;
655 break;
656 }
657 default: return CO_SDO_AC_NO_SUB;
658 }
659
660 co_sub_dn(sub, &val);
661
662 return 0;
663}
664
665static co_unsigned32_t
666co_1600_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
667{
668 assert(sub);
669 assert(req);
670 co_rpdo_t *pdo = data;
671 assert(pdo);
672 assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1600 + pdo->num - 1);
673
674 co_unsigned32_t ac = 0;
675
676 co_unsigned16_t type = co_sub_get_type(sub);
677 assert(!co_type_is_array(type));
678
679 union co_val val;
680 if (co_sdo_req_dn_val(req, type, &val, &ac) == -1)
681 return ac;
682
683 int valid = !(pdo->comm.cobid & CO_PDO_COBID_VALID);
684
685 if (!co_sub_get_subidx(sub)) {
686 assert(type == CO_DEFTYPE_UNSIGNED8);
687 co_unsigned8_t n = val.u8;
688 co_unsigned8_t n_old = co_sub_get_val_u8(sub);
689 if (n == n_old)
690 return 0;
691
692 // The PDO mapping cannot be changed when the PDO is valid.
693 if (valid)
694 return CO_SDO_AC_PARAM_VAL;
695
696 if (n <= CO_PDO_NUM_MAPS) {
697 size_t bits = 0;
698 for (size_t i = 1; i <= n; i++) {
699 co_unsigned32_t map = pdo->map.map[i - 1];
700 if (!map)
701 continue;
702
703 co_unsigned16_t idx = (map >> 16) & 0xffff;
704 co_unsigned8_t subidx = (map >> 8) & 0xff;
705 co_unsigned8_t len = map & 0xff;
706
707 // Check the PDO length.
708 if ((bits += len) > CAN_MAX_LEN * 8)
709 return CO_SDO_AC_PDO_LEN;
710
711 // Check whether the sub-object exists and can
712 // be mapped into a PDO (or is a valid dummy
713 // entry).
714 // clang-format off
715 if ((ac = co_dev_chk_rpdo(
716 pdo->dev, idx, subidx)))
717 // clang-format on
718 return ac;
719 }
720#if LELY_NO_CO_MPDO
721 } else {
722#else
723 } else if (n != CO_PDO_MAP_SAM_MPDO
724 && n != CO_PDO_MAP_DAM_MPDO) {
725#endif
726 return CO_SDO_AC_PARAM_VAL;
727 }
728
729 pdo->map.n = n;
730 } else {
731 assert(type == CO_DEFTYPE_UNSIGNED32);
732 co_unsigned32_t map = val.u32;
733 co_unsigned32_t map_old = co_sub_get_val_u32(sub);
734 if (map == map_old)
735 return 0;
736
737 // The PDO mapping cannot be changed when the PDO is valid or
738 // sub-index 0x00 is non-zero.
739 if (valid || pdo->map.n)
740 return CO_SDO_AC_PARAM_VAL;
741
742 if (map) {
743 co_unsigned16_t idx = (map >> 16) & 0xffff;
744 co_unsigned8_t subidx = (map >> 8) & 0xff;
745 // Check whether the sub-object exists and can be mapped
746 // into a PDO (or is a valid dummy entry).
747 if ((ac = co_dev_chk_rpdo(pdo->dev, idx, subidx)))
748 return ac;
749 }
750
751 pdo->map.map[co_sub_get_subidx(sub) - 1] = map;
752 }
753
754 co_sub_dn(sub, &val);
755
756 return 0;
757}
758
759static int
760co_rpdo_recv(const struct can_msg *msg, void *data)
761{
762 assert(msg);
763 assert(!(msg->flags & CAN_FLAG_RTR));
764#if !LELY_NO_CANFD
765 assert(!(msg->flags & CAN_FLAG_EDL));
766#endif
767
768 co_rpdo_t *pdo = data;
769 assert(pdo);
770
771 // Reset the event timer.
773
774 if (pdo->comm.trans <= 0xf0) {
775 // In case of a synchronous RPDO, save the frame to be processed
776 // after the next SYNC object.
777 if (!pdo->swnd) {
778 pdo->sync = 1;
779 pdo->msg = *msg;
780 }
781 } else if (pdo->comm.trans >= 0xfe) {
782 // In case of an event-driven RPDO, process the frame directly.
783 co_rpdo_read_frame(pdo, msg);
784 }
785
786 return 0;
787}
788
789static int
790co_rpdo_timer_event(const struct timespec *tp, void *data)
791{
792 (void)tp;
793 co_rpdo_t *pdo = data;
794 assert(pdo);
795
796 trace("RPDO %d: no PDO received in synchronous window", pdo->num);
797
798 // Generate an error if an RPDO timeout occurred.
799 if (pdo->err)
800 pdo->err(pdo, 0x8250, 0x10, pdo->err_data);
801
802 return 0;
803}
804
805static int
806co_rpdo_timer_swnd(const struct timespec *tp, void *data)
807{
808 (void)tp;
809 co_rpdo_t *pdo = data;
810 assert(pdo);
811
812 // The synchronous time window has expired.
813 pdo->swnd = 1;
814
815 return 0;
816}
817
818static co_unsigned32_t
819co_rpdo_read_frame(co_rpdo_t *pdo, const struct can_msg *msg)
820{
821 assert(pdo);
822 assert(msg);
823
824 size_t n = MIN(msg->len, CAN_MAX_LEN);
825 co_unsigned32_t ac = co_pdo_dn(
826 &pdo->map, pdo->dev, &pdo->req, msg->data, n, 1);
827
828#if !defined(NDEBUG) && !LELY_NO_STDIO && !LELY_NO_DIAG
829 if (ac)
830 trace("RPDO %d: PDO error %08" PRIX32 " (%s)", pdo->num, ac,
831 co_sdo_ac2str(ac));
832#endif
833
834 // Invoke the user-defined callback function.
835 if (pdo->ind)
836 pdo->ind(pdo, ac, msg->data, n, pdo->ind_data);
837
838 if (pdo->err) {
839 if (ac == CO_SDO_AC_PDO_LEN) {
840 // Generate an error message if the PDO was not
841 // processed because too few bytes were available.
842 pdo->err(pdo, 0x8210, 0x10, pdo->err_data);
843 } else if (!ac && pdo->map.n <= CO_PDO_NUM_MAPS) {
844 size_t offset = 0;
845 for (size_t i = 0; i < pdo->map.n; i++)
846 offset += (pdo->map.map[i]) & 0xff;
847 if ((offset + 7) / 8 < n)
848 // Generate an error message if the PDO length
849 // exceeds the mapping.
850 pdo->err(pdo, 0x8220, 0x10, pdo->err_data);
851#if !LELY_NO_CO_MPDO
852 } else if ((ac == CO_SDO_AC_NO_OBJ || ac == CO_SDO_AC_NO_SUB)
853 && pdo->map.n == 0xff) {
854 // In case of a DAM-MPDO, generate an error message if
855 // the destination object does not exist.
856 pdo->err(pdo, 0x8230, 0x10, pdo->err_data);
857#endif
858 }
859 }
860
861 return ac;
862}
863
864#endif // !LELY_NO_CO_RPDO
@ CAN_FLAG_IDE
The Identifier Extension (IDE) flag.
Definition msg.h:43
@ CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames).
Definition msg.h:48
#define CAN_MASK_EID
The mask used to extract the 29-bit Extended Identifier from a CAN frame.
Definition msg.h:34
#define CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
Definition msg.h:72
#define CAN_MASK_BID
The mask used to extract the 11-bit Base Identifier from a CAN frame.
Definition msg.h:31
#define CAN_MSG_INIT
The static initializer for can_msg.
Definition msg.h:113
This header file is part of the CANopen library; it contains the device description declarations.
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
This header file is part of the utilities library; it contains the native and platform-independent er...
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition errnum.c:810
@ ERRNUM_INVAL
Invalid argument.
Definition errnum.h:132
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
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition errnum.h:424
This header file is part of the CANopen library; it contains the Service Data Object (SDO) declaratio...
int co_sdo_req_dn_val(struct co_sdo_req *req, co_unsigned16_t type, void *val, co_unsigned32_t *pac)
Copies the next segment of the specified CANopen SDO download request to the internal buffer and,...
Definition sdo.c:170
void co_sdo_req_fini(struct co_sdo_req *req)
Finalizes a CANopen SDO upload/download request.
Definition sdo.c:121
#define CO_SDO_AC_NO_OBJ
SDO abort code: Object does not exist in the object dictionary.
Definition sdo.h:93
const char * co_sdo_ac2str(co_unsigned32_t ac)
Returns a string describing an SDO abort code.
Definition sdo.c:57
#define CO_SDO_AC_NO_SUB
SDO abort code: Sub-index does not exist.
Definition sdo.h:132
#define CO_SDO_AC_PARAM_VAL
SDO abort code: Invalid value for parameter (download only).
Definition sdo.h:135
#define CO_SDO_AC_PDO_LEN
SDO abort code: The number and length of the objects to be mapped would exceed the PDO length.
Definition sdo.h:102
void co_sdo_req_init(struct co_sdo_req *req)
Initializes a CANopen SDO upload/download request.
Definition sdo.c:109
#define CO_SDO_AC_NO_WRITE
SDO abort code: Attempt to write a read only object.
Definition sdo.h:90
#define MIN(a, b)
Returns the minimum of a and b.
Definition util.h:57
void can_timer_stop(can_timer_t *timer)
Stops a CAN timer and unregisters it with a network interface.
Definition net.c:462
int can_net_send(can_net_t *net, const struct can_msg *msg)
Sends a CAN frame from a network interface.
Definition net.c:300
void can_timer_start(can_timer_t *timer, can_net_t *net, const struct timespec *start, const struct timespec *interval)
Starts a CAN timer and registers it with a network interface.
Definition net.c:431
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition net.c:376
void can_net_get_time(const can_net_t *net, struct timespec *tp)
Retrieves the current time of a CAN network interface.
Definition net.c:196
void can_timer_set_func(can_timer_t *timer, can_timer_func_t *func, void *data)
Sets the callback function invoked when a CAN timer is triggered.
Definition net.c:422
void can_recv_stop(can_recv_t *recv)
Stops a CAN frame receiver from processing frames and unregisters it with the network interface.
Definition net.c:609
void can_recv_set_func(can_recv_t *recv, can_recv_func_t *func, void *data)
Sets the callback function used to process CAN frames with a receiver.
Definition net.c:578
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition net.c:558
void can_timer_timeout(can_timer_t *timer, can_net_t *net, int timeout)
Starts a CAN timer and registers it with a network interface.
Definition net.c:478
void can_recv_start(can_recv_t *recv, can_net_t *net, uint_least32_t id, uint_least8_t flags)
Registers a CAN frame receiver with a network interface and starts processing frames.
Definition net.c:587
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition net.c:533
void can_timer_destroy(can_timer_t *timer)
Destroys a CAN timer.
Definition net.c:401
This header file is part of the CANopen library; it contains the object dictionary declarations.
co_sub_t * co_obj_first_sub(const co_obj_t *obj)
Finds the first sub-object (with the lowest sub-index) in a CANopen object.
Definition obj.c:249
co_unsigned8_t co_sub_get_subidx(const co_sub_t *sub)
Returns the sub-index of a CANopen sub-object.
Definition obj.c:559
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition obj.c:164
int co_sub_dn(co_sub_t *sub, void *val)
Downloads (moves) a value into a CANopen sub-object if the refuse-write-on-download flag (CO_OBJ_FLAG...
Definition obj.c:996
void co_obj_set_dn_ind(co_obj_t *obj, co_sub_dn_ind_t *ind, void *data)
Sets the download indication function for a CANopen object.
Definition obj.c:389
co_sub_t * co_sub_next(const co_sub_t *sub)
Finds the next sub-object in a CANopen object.
Definition obj.c:542
co_obj_t * co_sub_get_obj(const co_sub_t *sub)
Returns the a pointer to the CANopen object containing the specified sub-object.
Definition obj.c:551
co_unsigned16_t co_sub_get_type(const co_sub_t *sub)
Returns the data type of a CANopen sub-object.
Definition obj.c:603
co_unsigned32_t co_dev_chk_rpdo(const co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx)
Checks if the specified object is valid and can be mapped into a Receive-PDO.
Definition pdo.c:51
#define CO_PDO_NUM_MAPS
The maximum number of mapped application objects in a single PDO.
Definition pdo.h:34
#define CO_PDO_COBID_FRAME
The bit in the PDO COB-ID specifying whether to use an 11-bit (0) or 29-bit (1) CAN-ID.
Definition pdo.h:46
#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
#define CO_PDO_MAP_DAM_MPDO
The value of sub-index 0 of the PDO mapping parameter record indicating a a destination address mode ...
Definition pdo.h:58
co_unsigned32_t co_pdo_dn(const struct co_pdo_map_par *par, co_dev_t *dev, struct co_sdo_req *req, const uint_least8_t *buf, size_t n, int chk)
Writes mapped PDO values to the object dictionary through a local SDO download request.
Definition pdo.c:368
#define CO_PDO_MAP_SAM_MPDO
The value of sub-index 0 of the PDO mapping parameter record indicating a a source address mode multi...
Definition pdo.h:52
void co_rpdo_get_err(const co_rpdo_t *pdo, co_rpdo_err_t **perr, void **pdata)
Retrieves the error handling function of a Receive-PDO service.
Definition rpdo.c:452
static void co_rpdo_init_timer_event(co_rpdo_t *pdo)
Initializes the CAN timer for deadline monitoring of a Receive-PDO service.
Definition rpdo.c:541
int co_rpdo_rtr(co_rpdo_t *pdo)
Requests the transmission of a PDO.
Definition rpdo.c:472
static int co_rpdo_timer_event(const struct timespec *tp, void *data)
The CAN timer callback function for deadline monitoring of a Receive-PDO service.
Definition rpdo.c:790
void co_rpdo_stop(co_rpdo_t *pdo)
Stops a Receive-PDO service.
Definition rpdo.c:356
int co_rpdo_is_stopped(const co_rpdo_t *pdo)
Retuns 1 if the specified Receive-PDO service is stopped, and 0 if not.
Definition rpdo.c:384
static int co_rpdo_timer_swnd(const struct timespec *tp, void *data)
The CAN timer callback function for the synchronous time window of a Receive-PDO service.
Definition rpdo.c:806
static void co_rpdo_init_recv(co_rpdo_t *pdo)
Initializes the CAN frame receiver of a Receive-PDO service.
Definition rpdo.c:519
co_dev_t * co_rpdo_get_dev(const co_rpdo_t *pdo)
Returns a pointer to the CANopen device of a Receive-PDO.
Definition rpdo.c:400
static void co_rpdo_init_timer_swnd(co_rpdo_t *pdo)
Initializes the CAN timer for the synchronous time window of a Receive-PDO service.
Definition rpdo.c:551
static co_unsigned32_t co_rpdo_read_frame(co_rpdo_t *pdo, const struct can_msg *msg)
Parses a CAN frame received by a Receive-PDO service and updates the corresponding objects in the obj...
Definition rpdo.c:819
int co_rpdo_sync(co_rpdo_t *pdo, co_unsigned8_t cnt)
Triggers the actuation of a received synchronous PDO.
Definition rpdo.c:493
void co_rpdo_set_err(co_rpdo_t *pdo, co_rpdo_err_t *err, void *data)
Sets the error handling function of a Receive-PDO service.
Definition rpdo.c:463
static co_unsigned32_t co_1400_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen objects 1400..15FF (RPDO communicat...
Definition rpdo.c:569
static co_unsigned32_t co_1600_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen objects 1600..17FF (RPDO mapping pa...
Definition rpdo.c:666
void co_rpdo_get_ind(const co_rpdo_t *pdo, co_rpdo_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a Receive-PDO error occurs.
Definition rpdo.c:432
can_net_t * co_rpdo_get_net(const co_rpdo_t *pdo)
Returns a pointer to the CAN network of a Receive-PDO.
Definition rpdo.c:392
co_unsigned16_t co_rpdo_get_num(const co_rpdo_t *pdo)
Returns the PDO number of a Receive-PDO.
Definition rpdo.c:408
static int co_rpdo_recv(const struct can_msg *msg, void *data)
The CAN receive callback function for a Receive-PDO service.
Definition rpdo.c:760
int co_rpdo_start(co_rpdo_t *pdo)
Starts a Receive-PDO service.
Definition rpdo.c:308
void co_rpdo_set_ind(co_rpdo_t *pdo, co_rpdo_ind_t *ind, void *data)
Sets the indication function invoked when a Receive-PDO error occurs.
Definition rpdo.c:443
const struct co_pdo_map_par * co_rpdo_get_map_par(const co_rpdo_t *pdo)
Returns a pointer to the PDO mapping parameter record of a Receive-PDO.
Definition rpdo.c:424
const struct co_pdo_comm_par * co_rpdo_get_comm_par(const co_rpdo_t *pdo)
Returns a pointer to the PDO communication parameter record of a Receive-PDO.
Definition rpdo.c:416
co_rpdo_t * co_rpdo_create(can_net_t *net, co_dev_t *dev, co_unsigned16_t num)
Creates a new CANopen Receive-PDO service.
Definition rpdo.c:271
void co_rpdo_destroy(co_rpdo_t *rpdo)
Destroys a CANopen Receive-PDO service.
Definition rpdo.c:298
This header file is part of the CANopen library; it contains the Receive-PDO declarations.
void co_rpdo_err_t(co_rpdo_t *pdo, co_unsigned16_t eec, co_unsigned8_t er, void *data)
The type of a CANopen Receive-PDO error handling function, invoked in case of a timeout or length mis...
Definition rpdo.h:56
void co_rpdo_ind_t(co_rpdo_t *pdo, co_unsigned32_t ac, const void *ptr, size_t n, void *data)
The type of a CANopen Receive-PDO indication function, invoked when a PDO is received or an error occ...
Definition rpdo.h:44
This is the internal header file of the CANopen library.
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....
A CAN network interface.
Definition net.c:37
A CAN frame receiver.
Definition net.c:86
A CAN timer.
Definition net.c:63
A CANopen device.
Definition dev.h:30
A CANopen object.
Definition obj.h:31
A CANopen Receive-PDO.
Definition rpdo.c:44
void * ind_data
A pointer to user-specified data for ind.
Definition rpdo.c:74
can_net_t * net
A pointer to a CAN network interface.
Definition rpdo.c:46
struct co_sdo_req req
The CANopen SDO download request used for writing sub-objects.
Definition rpdo.c:70
can_timer_t * timer_swnd
A pointer to the CAN timer for the synchronous time window.
Definition rpdo.c:62
unsigned int sync
A flag indicating we're waiting for a SYNC object to process msg.
Definition rpdo.c:64
unsigned int swnd
A flag indicating the synchronous time window has expired.
Definition rpdo.c:66
can_timer_t * timer_event
A pointer to the CAN timer for deadline monitoring.
Definition rpdo.c:60
co_unsigned16_t num
The PDO number.
Definition rpdo.c:50
struct co_pdo_comm_par comm
The PDO communication parameter.
Definition rpdo.c:54
co_dev_t * dev
A pointer to a CANopen device.
Definition rpdo.c:48
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition rpdo.c:58
co_rpdo_ind_t * ind
A pointer to the indication function.
Definition rpdo.c:72
void * err_data
A pointer to user-specified data for err.
Definition rpdo.c:78
struct co_pdo_map_par map
The PDO mapping parameter.
Definition rpdo.c:56
co_rpdo_err_t * err
A pointer to the error handling function.
Definition rpdo.c:76
struct can_msg msg
A CAN frame waiting for a SYNC object to be processed.
Definition rpdo.c:68
int stopped
A flag specifying whether the Receive-PDO service is stopped.
Definition rpdo.c:52
A CANopen sub-object.
Definition obj.h:53
A CAN or CAN FD format frame.
Definition msg.h:87
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition msg.h:102
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition msg.h:89
uint_least8_t flags
The flags (any combination of CAN_FLAG_IDE, CAN_FLAG_RTR, CAN_FLAG_FDF, CAN_FLAG_BRS and CAN_FLAG_ESI...
Definition msg.h:94
uint_least8_t len
The number of bytes in data (or the requested number of bytes in case of a remote frame).
Definition msg.h:100
A PDO communication parameter record.
Definition pdo.h:64
co_unsigned8_t sync
SYNC start value.
Definition pdo.h:77
co_unsigned16_t inhibit
Inhibit time.
Definition pdo.h:72
co_unsigned16_t event
Event timer.
Definition pdo.h:75
co_unsigned32_t cobid
COB-ID.
Definition pdo.h:68
co_unsigned8_t trans
Transmission type.
Definition pdo.h:70
co_unsigned8_t n
Highest sub-index supported.
Definition pdo.h:66
A PDO mapping parameter record.
Definition pdo.h:90
co_unsigned8_t n
Number of mapped objects in PDO.
Definition pdo.h:92
co_unsigned32_t map[CO_PDO_NUM_MAPS]
An array of objects to be mapped.
Definition pdo.h:94
A CANopen SDO upload/download request.
Definition sdo.h:181
A time type with nanosecond resolution.
Definition time.h:88
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition type.h:47
int co_type_is_array(co_unsigned16_t type)
Returns 1 if the specified (static) data type is an array, and 0 if not.
Definition type.c:40
#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
A union of the CANopen static data types.
Definition val.h:273
This header file is part of the utilities library; it contains the time function declarations.
void timespec_add_usec(struct timespec *tp, uint_least64_t usec)
Adds usec microseconds to the time at tp.
Definition time.h:149
This header file is part of the CANopen library; it contains the CANopen value declarations.