Lely core libraries 1.9.2
tpdo.c
Go to the documentation of this file.
1
24#include "co.h"
25
26#ifndef LELY_NO_CO_TPDO
27
28#include <lely/can/buf.h>
29#include <lely/co/dev.h>
30#include <lely/co/obj.h>
31#include <lely/co/sdo.h>
32#include <lely/co/tpdo.h>
33#include <lely/co/val.h>
34#include <lely/util/errnum.h>
35#include <lely/util/time.h>
36
37#include <assert.h>
38#include <stdlib.h>
39
41struct __co_tpdo {
47 co_unsigned16_t num;
59 struct can_buf *buf;
63 unsigned int event : 1;
65 unsigned int swnd : 1;
67 co_unsigned8_t sync;
69 co_unsigned8_t cnt;
75 void *data;
76};
77
85static int co_tpdo_init_recv(co_tpdo_t *pdo);
86
94static int co_tpdo_init_timer_event(co_tpdo_t *pdo);
95
102static int co_tpdo_init_timer_swnd(co_tpdo_t *pdo);
103
111static int co_tpdo_init_buf(co_tpdo_t *pdo);
112
119static co_unsigned32_t co_1800_dn_ind(
120 co_sub_t *sub, struct co_sdo_req *req, void *data);
121
128static co_unsigned32_t co_1a00_dn_ind(
129 co_sub_t *sub, struct co_sdo_req *req, void *data);
130
136static int co_tpdo_recv(const struct can_msg *msg, void *data);
137
143static int co_tpdo_timer_event(const struct timespec *tp, void *data);
144
151static int co_tpdo_timer_swnd(const struct timespec *tp, void *data);
152
161static co_unsigned32_t co_tpdo_init_frame(co_tpdo_t *pdo, struct can_msg *msg);
162
163void *
164__co_tpdo_alloc(void)
165{
166 void *ptr = malloc(sizeof(struct __co_tpdo));
167 if (__unlikely(!ptr))
168 set_errc(errno2c(errno));
169 return ptr;
170}
171
172void
173__co_tpdo_free(void *ptr)
174{
175 free(ptr);
176}
177
178struct __co_tpdo *
179__co_tpdo_init(struct __co_tpdo *pdo, can_net_t *net, co_dev_t *dev,
180 co_unsigned16_t num)
181{
182 assert(pdo);
183 assert(net);
184 assert(dev);
185
186 int errc = 0;
187
188 if (__unlikely(!num || num > 512)) {
189 errc = errnum2c(ERRNUM_INVAL);
190 goto error_param;
191 }
192
193 // Find the PDO parameters in the object dictionary.
194 co_obj_t *obj_1800 = co_dev_find_obj(dev, 0x1800 + num - 1);
195 co_obj_t *obj_1a00 = co_dev_find_obj(dev, 0x1a00 + num - 1);
196 if (__unlikely(!obj_1800 || !obj_1a00)) {
197 errc = errnum2c(ERRNUM_INVAL);
198 goto error_param;
199 }
200
201 pdo->net = net;
202 pdo->dev = dev;
203 pdo->num = num;
204
205 // Copy the PDO communication parameter record.
206 memset(&pdo->comm, 0, sizeof(pdo->comm));
207 memcpy(&pdo->comm, co_obj_addressof_val(obj_1800),
208 MIN(co_obj_sizeof_val(obj_1800), sizeof(pdo->comm)));
209
210 // Copy the PDO mapping parameter record.
211 memset(&pdo->map, 0, sizeof(pdo->map));
212 memcpy(&pdo->map, co_obj_addressof_val(obj_1a00),
213 MIN(co_obj_sizeof_val(obj_1a00), sizeof(pdo->map)));
214
215 pdo->recv = NULL;
216
217 pdo->timer_event = NULL;
218 pdo->timer_swnd = NULL;
219
220 pdo->buf = NULL;
221
222 can_net_get_time(pdo->net, &pdo->inhibit);
223 pdo->event = 0;
224 pdo->swnd = 0;
225 pdo->sync = pdo->comm.sync;
226 pdo->cnt = 0;
227
228 co_sdo_req_init(&pdo->req);
229
230 pdo->ind = NULL;
231 pdo->data = NULL;
232
233 // Set the download indication functions PDO communication parameter
234 // record.
235 co_obj_set_dn_ind(obj_1800, &co_1800_dn_ind, pdo);
236
237 // Set the download indication functions PDO mapping parameter record.
238 co_obj_set_dn_ind(obj_1a00, &co_1a00_dn_ind, pdo);
239
240 if (__unlikely(co_tpdo_init_recv(pdo) == -1)) {
241 errc = get_errc();
242 goto error_init_recv;
243 }
244
245 if (__unlikely(co_tpdo_init_timer_event(pdo) == -1)) {
246 errc = get_errc();
247 goto error_init_timer_event;
248 }
249
250 if (__unlikely(co_tpdo_init_buf(pdo) == -1)) {
251 errc = get_errc();
252 goto error_init_buf;
253 }
254
255 return pdo;
256
257error_init_buf:
259error_init_timer_event:
261error_init_recv:
262 co_obj_set_dn_ind(obj_1a00, NULL, NULL);
263 co_obj_set_dn_ind(obj_1800, NULL, NULL);
264error_param:
265 set_errc(errc);
266 return NULL;
267}
268
269void
270__co_tpdo_fini(struct __co_tpdo *pdo)
271{
272 assert(pdo);
273 assert(pdo->num >= 1 && pdo->num <= 512);
274
275 // Remove the download indication functions PDO mapping parameter
276 // record.
277 co_obj_t *obj_1a00 = co_dev_find_obj(pdo->dev, 0x1a00 + pdo->num - 1);
278 assert(obj_1a00);
279 co_obj_set_dn_ind(obj_1a00, NULL, NULL);
280
281 // Remove the download indication functions PDO communication parameter
282 // record.
283 co_obj_t *obj_1800 = co_dev_find_obj(pdo->dev, 0x1800 + pdo->num - 1);
284 assert(obj_1800);
285 co_obj_set_dn_ind(obj_1800, NULL, NULL);
286
287 co_sdo_req_fini(&pdo->req);
288
289 can_buf_destroy(pdo->buf);
290
293
295}
296
297co_tpdo_t *
299{
300 trace("creating Transmit-PDO %d", num);
301
302 int errc = 0;
303
304 co_tpdo_t *pdo = __co_tpdo_alloc();
305 if (__unlikely(!pdo)) {
306 errc = get_errc();
307 goto error_alloc_pdo;
308 }
309
310 if (__unlikely(!__co_tpdo_init(pdo, net, dev, num))) {
311 errc = get_errc();
312 goto error_init_pdo;
313 }
314
315 return pdo;
316
317error_init_pdo:
318 __co_tpdo_free(pdo);
319error_alloc_pdo:
320 set_errc(errc);
321 return NULL;
322}
323
324void
326{
327 if (tpdo) {
328 trace("destroying Transmit-PDO %d", tpdo->num);
329 __co_tpdo_fini(tpdo);
330 __co_tpdo_free(tpdo);
331 }
332}
333
334can_net_t *
336{
337 assert(pdo);
338
339 return pdo->net;
340}
341
342co_dev_t *
344{
345 assert(pdo);
346
347 return pdo->dev;
348}
349
350co_unsigned16_t
352{
353 assert(pdo);
354
355 return pdo->num;
356}
357
358const struct co_pdo_comm_par *
360{
361 assert(pdo);
362
363 return &pdo->comm;
364}
365
366const struct co_pdo_map_par *
368{
369 assert(pdo);
370
371 return &pdo->map;
372}
373
374void
375co_tpdo_get_ind(const co_tpdo_t *pdo, co_tpdo_ind_t **pind, void **pdata)
376{
377 assert(pdo);
378
379 if (pind)
380 *pind = pdo->ind;
381 if (pdata)
382 *pdata = pdo->data;
383}
384
385void
387{
388 assert(pdo);
389
390 pdo->ind = ind;
391 pdo->data = data;
392}
393
394int
396{
397 assert(pdo);
398
399 // Ignore events if the transmission type is synchronous.
400 if (pdo->comm.trans && pdo->comm.trans < 0xfd)
401 return 0;
402
403 if (!pdo->comm.trans) {
404 // Ignore events occurring after the synchronous time window has
405 // expired.
406 if (!pdo->event)
407 pdo->event = !pdo->swnd;
408 } else if (pdo->comm.trans >= 0xfe) {
409 if (pdo->comm.inhibit) {
410 // Check whether the inhibit time has passed.
411 struct timespec now;
412 can_net_get_time(pdo->net, &now);
413 if (timespec_cmp(&now, &pdo->inhibit) < 0) {
415 return -1;
416 }
417 pdo->inhibit = now;
418 }
419
420 // In case of an event-driven TPDO, send the frame right away.
421 struct can_msg msg;
422 if (__unlikely(co_tpdo_init_frame(pdo, &msg)))
423 return -1;
424 if (__unlikely(can_net_send(pdo->net, &msg) == -1))
425 return -1;
426
427 if (pdo->comm.inhibit)
429 &pdo->inhibit, pdo->comm.inhibit * 100);
430 }
431
432 return co_tpdo_init_timer_event(pdo);
433}
434
435int
436co_tpdo_sync(co_tpdo_t *pdo, co_unsigned8_t cnt)
437{
438 assert(pdo);
439
440 if (__unlikely(cnt > 240)) {
442 return -1;
443 }
444
445 // Check whether the PDO exists and is valid.
446 if (pdo->comm.cobid & CO_PDO_COBID_VALID)
447 return 0;
448
449 // Ignore SYNC objects if the transmission type is not synchronous.
450 if (pdo->comm.trans > 0xf0 && pdo->comm.trans != 0xfc)
451 return 0;
452
453 // Reset the time window for synchronous PDOs.
454 pdo->swnd = 0;
456
457 // Wait for the SYNC counter to equal the SYNC start value.
458 if (pdo->sync && cnt) {
459 if (pdo->sync != cnt)
460 return 0;
461 pdo->sync = 0;
462 pdo->cnt = 0;
463 }
464
465 if (!pdo->comm.trans) {
466 // In case of a synchronous (acyclic) TPDO, do nothing unless an
467 // event occurred.
468 if (!pdo->event)
469 return 0;
470 pdo->event = 0;
471 } else if (pdo->comm.trans <= 0xf0) {
472 // In case of a synchronous (cyclic) TPDO, do nothing unless the
473 // n-th SYNC object has been received.
474 if (++pdo->cnt < pdo->comm.trans)
475 return 0;
476 pdo->cnt = 0;
477 }
478
479 struct can_msg msg;
480 if (__unlikely(co_tpdo_init_frame(pdo, &msg)))
481 return -1;
482
483 if (pdo->comm.trans <= 0xf0) {
484 if (__unlikely(can_net_send(pdo->net, &msg) == -1))
485 return -1;
486 } else if (pdo->comm.trans == 0xfc) {
487 if (__unlikely(!pdo->buf)) {
489 return -1;
490 }
491 // In case of an RTR-only (synchronous) TPDO, buffer the frame
492 // instead of sending it right away.
493 if (__unlikely(!can_buf_write(pdo->buf, &msg, 1))) {
494 if (__unlikely(!can_buf_reserve(pdo->buf, 1)))
495 return -1;
496 can_buf_write(pdo->buf, &msg, 1);
497 }
498 }
499
500 return 0;
501}
502
503void
504co_tpdo_get_next(const co_tpdo_t *pdo, struct timespec *tp)
505{
506 assert(pdo);
507
508 if (tp)
509 *tp = pdo->inhibit;
510}
511
512static int
514{
515 assert(pdo);
516
517 // clang-format off
518 if (!(pdo->comm.cobid & CO_PDO_COBID_VALID) && (pdo->comm.trans == 0xfc
519 || pdo->comm.trans == 0xfd)) {
520 // clang-format on
521 if (!pdo->recv) {
522 pdo->recv = can_recv_create();
523 if (__unlikely(!pdo->recv))
524 return -1;
526 }
527 // Register the receiver under the specified CAN-ID.
528 uint32_t id = pdo->comm.cobid;
529 uint8_t flags = 0;
530 if (id & CO_PDO_COBID_FRAME) {
531 id &= CAN_MASK_EID;
533 } else {
534 id &= CAN_MASK_BID;
535 }
536 can_recv_start(pdo->recv, pdo->net, id, flags);
537 } else if (pdo->recv) {
539 pdo->recv = NULL;
540 }
541
542 return 0;
543}
544
545static int
547{
548 assert(pdo);
549
550 if (!(pdo->comm.cobid & CO_PDO_COBID_VALID)
551 && (!pdo->comm.trans || pdo->comm.trans >= 0xfe)
552 && pdo->comm.event) {
553 if (!pdo->timer_event) {
555 if (__unlikely(!pdo->timer_event))
556 return -1;
558 &co_tpdo_timer_event, pdo);
559 }
560 // Reset the event timer.
561 can_timer_timeout(pdo->timer_event, pdo->net, pdo->comm.event);
562 } else if (pdo->timer_event) {
564 pdo->timer_event = NULL;
565 }
566
567 return 0;
568}
569
570static int
572{
573 assert(pdo);
574
575 // Ignore the synchronous window length unless the TPDO is valid and
576 // synchronous.
577 co_unsigned32_t swnd = co_dev_get_val_u32(pdo->dev, 0x1007, 0x00);
578 if (!(pdo->comm.cobid & CO_PDO_COBID_VALID)
579 && (pdo->comm.trans <= 0xf0 || pdo->comm.trans == 0xfc)
580 && swnd) {
581 if (!pdo->timer_swnd) {
583 if (__unlikely(!pdo->timer_swnd))
584 return -1;
586 pdo);
587 }
588 can_timer_timeout(pdo->timer_swnd, pdo->net, swnd);
589 } else if (pdo->timer_swnd) {
591 pdo->timer_swnd = NULL;
592 }
593
594 return 0;
595}
596
597static int
599{
600 assert(pdo);
601
602 if (!(pdo->comm.cobid & CO_PDO_COBID_VALID)
603 && (pdo->comm.trans == 0xfd)) {
604 if (!pdo->buf) {
605 pdo->buf = can_buf_create(0);
606 if (__unlikely(!pdo->buf))
607 return -1;
608 }
609 } else if (pdo->buf) {
610 can_buf_destroy(pdo->buf);
611 pdo->buf = NULL;
612 }
613
614 return 0;
615}
616
617static co_unsigned32_t
618co_1800_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
619{
620 assert(sub);
621 assert(req);
622 co_tpdo_t *pdo = data;
623 assert(pdo);
624 assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1800 + pdo->num - 1);
625
626 co_unsigned32_t ac = 0;
627
628 co_unsigned16_t type = co_sub_get_type(sub);
629 union co_val val;
630 if (__unlikely(co_sdo_req_dn_val(req, type, &val, &ac) == -1))
631 return ac;
632
633 switch (co_sub_get_subidx(sub)) {
634 case 0: ac = CO_SDO_AC_NO_WRITE; goto error;
635 case 1: {
636 assert(type == CO_DEFTYPE_UNSIGNED32);
637 co_unsigned32_t cobid = val.u32;
638 co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
639 if (cobid == cobid_old)
640 goto error;
641
642 // The CAN-ID cannot be changed when the PDO is and remains
643 // valid.
644 int valid = !(cobid & CO_PDO_COBID_VALID);
645 int valid_old = !(cobid_old & CO_PDO_COBID_VALID);
646 uint32_t canid = cobid & CAN_MASK_EID;
647 uint32_t canid_old = cobid_old & CAN_MASK_EID;
648 if (__unlikely(valid && valid_old && canid != canid_old)) {
650 goto error;
651 }
652
653 // A 29-bit CAN-ID is only valid if the frame bit is set.
654 // clang-format off
655 if (__unlikely(!(cobid & CO_PDO_COBID_FRAME)
656 && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))) {
657 // clang-format on
659 goto error;
660 }
661
662 pdo->comm.cobid = cobid;
663
664 if (valid && !valid_old) {
665 can_net_get_time(pdo->net, &pdo->inhibit);
666 pdo->event = 0;
667 pdo->sync = pdo->comm.sync;
668 pdo->cnt = 0;
669 }
670
674 co_tpdo_init_buf(pdo);
675 break;
676 }
677 case 2: {
678 assert(type == CO_DEFTYPE_UNSIGNED8);
679 co_unsigned8_t trans = val.u8;
680 co_unsigned8_t trans_old = co_sub_get_val_u8(sub);
681 if (trans == trans_old)
682 goto error;
683
684 // Transmission types 0xF1..0xFB are reserved.
685 if (__unlikely(trans > 0xf0 && trans < 0xfc)) {
687 goto error;
688 }
689
690 // Check whether RTR is allowed on this PDO.
691 // clang-format off
692 if (__unlikely((trans == 0xfc || trans == 0xfd)
693 && (pdo->comm.cobid & CO_PDO_COBID_RTR))) {
694 // clang-format on
696 goto error;
697 }
698
699 pdo->comm.trans = trans;
700
701 pdo->event = 0;
702
706 co_tpdo_init_buf(pdo);
707 break;
708 }
709 case 3: {
710 assert(type == CO_DEFTYPE_UNSIGNED16);
711 co_unsigned16_t inhibit = val.u16;
712 co_unsigned16_t inhibit_old = co_sub_get_val_u16(sub);
713 if (inhibit == inhibit_old)
714 goto error;
715
716 // The inhibit time cannot be changed while the PDO exists and
717 // is valid.
718 if (__unlikely(!(pdo->comm.cobid & CO_PDO_COBID_VALID))) {
720 goto error;
721 }
722
723 pdo->comm.inhibit = inhibit;
724 break;
725 }
726 case 5: {
727 assert(type == CO_DEFTYPE_UNSIGNED16);
728 co_unsigned16_t event = val.u16;
729 co_unsigned16_t event_old = co_sub_get_val_u16(sub);
730 if (event == event_old)
731 goto error;
732
733 pdo->comm.event = event;
734
736 break;
737 }
738 case 6: {
739 assert(type == CO_DEFTYPE_UNSIGNED8);
740 co_unsigned8_t sync = val.u8;
741 co_unsigned8_t sync_old = co_sub_get_val_u8(sub);
742 if (sync == sync_old)
743 goto error;
744
745 // The SYNC start value cannot be changed while the PDO exists
746 // and is valid.
747 if (__unlikely(!(pdo->comm.cobid & CO_PDO_COBID_VALID))) {
749 goto error;
750 }
751
752 pdo->comm.sync = sync;
753 break;
754 }
755 default: ac = CO_SDO_AC_NO_SUB; goto error;
756 }
757
758 co_sub_dn(sub, &val);
759error:
760 co_val_fini(type, &val);
761 return ac;
762}
763
764static co_unsigned32_t
765co_1a00_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
766{
767 assert(sub);
768 assert(req);
769 co_tpdo_t *pdo = data;
770 assert(pdo);
771 assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1a00 + pdo->num - 1);
772
773 co_unsigned32_t ac = 0;
774
775 co_unsigned16_t type = co_sub_get_type(sub);
776 union co_val val;
777 if (__unlikely(co_sdo_req_dn_val(req, type, &val, &ac) == -1))
778 return ac;
779
780 int valid = !(pdo->comm.cobid & CO_PDO_COBID_VALID);
781
782 if (!co_sub_get_subidx(sub)) {
783 assert(type == CO_DEFTYPE_UNSIGNED8);
784 co_unsigned8_t n = val.u8;
785 co_unsigned8_t n_old = co_sub_get_val_u8(sub);
786 if (n == n_old)
787 goto error;
788
789 // The PDO mapping cannot be changed when the PDO is valid.
790 if (__unlikely(valid || n > 0x40)) {
792 goto error;
793 }
794
795 size_t bits = 0;
796 for (size_t i = 1; i <= n; i++) {
797 co_unsigned32_t map = pdo->map.map[i - 1];
798 co_unsigned16_t idx = (map >> 16) & 0xffff;
799 co_unsigned8_t subidx = (map >> 8) & 0xff;
800 co_unsigned8_t len = map & 0xff;
801
802 // Check the PDO length.
803 if (__unlikely((bits += len) > CAN_MAX_LEN * 8)) {
805 goto error;
806 }
807
808 // Check whether the sub-object exists and can be mapped
809 // into a PDO.
810 ac = co_dev_chk_tpdo(pdo->dev, idx, subidx);
811 if (__unlikely(ac))
812 goto error;
813 }
814
815 pdo->map.n = n;
816 } else {
817 assert(type == CO_DEFTYPE_UNSIGNED32);
818 co_unsigned32_t map = val.u32;
819 co_unsigned32_t map_old = co_sub_get_val_u32(sub);
820 if (map == map_old)
821 goto error;
822
823 // The PDO mapping cannot be changed when the PDO is valid or
824 // sub-index 0x00 is non-zero.
825 if (__unlikely(valid || pdo->map.n)) {
827 goto error;
828 }
829
830 co_unsigned16_t idx = (map >> 16) & 0xffff;
831 co_unsigned8_t subidx = (map >> 8) & 0xff;
832 // Check whether the sub-object exists and can be mapped into a
833 // PDO.
834 ac = co_dev_chk_tpdo(pdo->dev, idx, subidx);
835 if (__unlikely(ac))
836 goto error;
837
838 pdo->map.map[co_sub_get_subidx(sub) - 1] = map;
839 }
840
841 co_sub_dn(sub, &val);
842error:
843 co_val_fini(type, &val);
844 return ac;
845}
846
847static int
848co_tpdo_recv(const struct can_msg *_msg, void *data)
849{
850 assert(_msg);
851 co_tpdo_t *pdo = data;
852 assert(pdo);
853
854 if (__unlikely(!(_msg->flags & CAN_FLAG_RTR)))
855 return 0;
856
857 struct can_msg msg;
858 switch (pdo->comm.trans) {
859 case 0xfc:
860 // Send a CAN frame from the buffer if available, otherwise
861 // fall through to the event-driven case.
862 if (pdo->buf && can_buf_read(pdo->buf, &msg, 1)) {
863 can_net_send(pdo->net, &msg);
864 break;
865 }
866 // ... falls through ...
867 case 0xfd: {
868 co_unsigned32_t ac = co_tpdo_init_frame(pdo, &msg);
869 if (__likely(!ac))
870 can_net_send(pdo->net, &msg);
871 if (pdo->ind)
872 pdo->ind(pdo, ac, ac ? NULL : msg.data,
873 ac ? 0 : msg.len, pdo->data);
874 }
875 default: break;
876 }
877
878 return 0;
879}
880
881static int
882co_tpdo_timer_event(const struct timespec *tp, void *data)
883{
884 (void)tp;
885 co_tpdo_t *pdo = data;
886 assert(pdo);
887
888 co_tpdo_event(pdo);
889
890 return 0;
891}
892
893static int
894co_tpdo_timer_swnd(const struct timespec *tp, void *data)
895{
896 (void)tp;
897 co_tpdo_t *pdo = data;
898 assert(pdo);
899
900 trace("TPDO %d: no event occurred in synchronous window", pdo->num);
901
902 if (pdo->ind)
903 pdo->ind(pdo, CO_SDO_AC_TIMEOUT, NULL, 0, pdo->data);
904
905 return 0;
906}
907
908static co_unsigned32_t
910{
911 assert(pdo);
912 assert(msg);
913
914 *msg = (struct can_msg)CAN_MSG_INIT;
915 msg->id = pdo->comm.cobid;
916 if (pdo->comm.cobid & CO_PDO_COBID_FRAME) {
917 msg->id &= CAN_MASK_EID;
918 msg->id |= CAN_FLAG_IDE;
919 } else {
920 msg->id &= CAN_MASK_BID;
921 }
922
923 size_t n = CAN_MAX_LEN;
924 co_unsigned32_t ac = co_pdo_up(
925 &pdo->map, pdo->dev, &pdo->req, msg->data, &n);
926 if (__unlikely(ac))
927 return ac;
928 msg->len = n;
929
930 return 0;
931}
932
933#endif // !LELY_NO_CO_TPDO
This header file is part of the CAN library; it contains the CAN frame buffer declarations.
struct can_buf * can_buf_create(size_t size)
Allocates and initializes a CAN frame buffer.
Definition: buf.c:75
size_t can_buf_reserve(struct can_buf *buf, size_t n)
Resizes a CAN frame buffer, if necessary, to make room for at least n additional frames.
Definition: buf.c:111
size_t can_buf_read(struct can_buf *buf, struct can_msg *ptr, size_t n)
Reads, and removes, frames from a CAN frame buffer.
Definition: buf.h:268
size_t can_buf_write(struct can_buf *buf, const struct can_msg *ptr, size_t n)
Writes frames to a CAN frame buffer.
Definition: buf.h:300
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:825
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:129
@ ERRNUM_AGAIN
Resource unavailable, try again.
Definition: errnum.h:86
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
#define __likely(x)
Indicates to the compiler that the expression is most-likely true.
Definition: features.h:273
This header file is part of the CANopen library; it contains the object dictionary declarations.
co_unsigned8_t co_sub_get_subidx(const co_sub_t *sub)
Returns the sub-index of a CANopen sub-object.
Definition: obj.c:466
void * co_obj_addressof_val(const co_obj_t *obj)
Returns the address of the value of a CANopen object.
Definition: obj.c:275
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition: obj.c:136
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:832
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:336
co_obj_t * co_sub_get_obj(const co_sub_t *sub)
Returns the a pointer to the CANopen object containing the specified sub-object.
Definition: obj.c:458
size_t co_obj_sizeof_val(const co_obj_t *obj)
Returns size (in bytes) of the value of a CANopen object.
Definition: obj.c:281
co_unsigned16_t co_sub_get_type(const co_sub_t *sub)
Returns the data type of a CANopen sub-object.
Definition: obj.c:508
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:165
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_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_TIMEOUT
SDO abort code: SDO protocol timed out.
Definition: sdo.h:66
#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
#define CAN_MASK_EID
The mask used to extract the 29-bit Extended Identifier from a CAN frame.
Definition: msg.h:34
#define CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames).
Definition: msg.h:47
#define CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
Definition: msg.h:73
#define CAN_FLAG_IDE
The Identifier Extension (IDE) flag.
Definition: msg.h:41
#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:114
int can_net_send(can_net_t *net, const struct can_msg *msg)
Sends a CAN frame from a network interface.
Definition: net.c:308
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition: net.c:382
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:204
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:428
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:582
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition: net.c:562
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:484
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:591
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition: net.c:537
void can_timer_destroy(can_timer_t *timer)
Destroys a CAN timer.
Definition: net.c:407
co_unsigned32_t co_pdo_up(const struct co_pdo_map_par *par, const co_dev_t *dev, struct co_sdo_req *req, uint8_t *buf, size_t *pn)
Reads mapped PDO values from the object dictionary through a local SDO upload request.
Definition: pdo.c:305
co_unsigned32_t co_dev_chk_tpdo(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 Transmit-PDO.
Definition: pdo.c:120
#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:37
#define CO_PDO_COBID_VALID
The bit in the PDO COB-ID specifying whether the PDO exists and is valid.
Definition: pdo.h:28
#define CO_PDO_COBID_RTR
The bit in the PDO COB-ID specifying whether RTR is allowed.
Definition: pdo.h:31
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....
A CAN network interface.
Definition: net.c:37
A CAN frame receiver.
Definition: net.c:99
A CAN timer.
Definition: net.c:63
A CANopen device.
Definition: dev.c:38
A CANopen object.
Definition: obj.h:32
A CANopen sub-object.
Definition: obj.h:54
A CANopen Transmit-PDO.
Definition: tpdo.c:41
struct co_sdo_req req
The CANopen SDO upload request used for reading sub-objects.
Definition: tpdo.c:71
unsigned int swnd
A flag indicating the synchronous time window has expired.
Definition: tpdo.c:65
struct co_pdo_map_par map
The PDO mapping parameter.
Definition: tpdo.c:51
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: tpdo.c:53
co_unsigned16_t num
The PDO number.
Definition: tpdo.c:47
struct can_buf * buf
A CAN frame buffer.
Definition: tpdo.c:59
struct co_pdo_comm_par comm
The PDO communication parameter.
Definition: tpdo.c:49
co_dev_t * dev
A pointer to a CANopen device.
Definition: tpdo.c:45
co_unsigned8_t sync
The SYNC start value.
Definition: tpdo.c:67
unsigned int event
A flag indicating the occurrence of an event.
Definition: tpdo.c:63
co_unsigned8_t cnt
The SYNC counter value.
Definition: tpdo.c:69
co_tpdo_ind_t * ind
A pointer to the indication function.
Definition: tpdo.c:73
can_net_t * net
A pointer to a CAN network interface.
Definition: tpdo.c:43
struct timespec inhibit
The time at which the next event-driven TPDO may be sent.
Definition: tpdo.c:61
void * data
A pointer to user-specified data for ind.
Definition: tpdo.c:75
can_timer_t * timer_event
A pointer to the CAN timer for events.
Definition: tpdo.c:55
can_timer_t * timer_swnd
A pointer to the CAN timer for the synchronous time window.
Definition: tpdo.c:57
A CAN frame buffer.
Definition: buf.h:47
A CAN or CAN FD format frame.
Definition: msg.h:88
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition: msg.h:103
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition: msg.h:90
uint_least8_t flags
The flags (any combination of CAN_FLAG_IDE, CAN_FLAG_RTR, CAN_FLAG_EDL, CAN_FLAG_BRS and CAN_FLAG_ESI...
Definition: msg.h:95
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:101
A PDO communication parameter record.
Definition: pdo.h:43
co_unsigned8_t sync
SYNC start value.
Definition: pdo.h:56
co_unsigned16_t inhibit
Inhibit time.
Definition: pdo.h:51
co_unsigned16_t event
Event timer.
Definition: pdo.h:54
co_unsigned32_t cobid
COB-ID.
Definition: pdo.h:47
co_unsigned8_t trans
Transmission type.
Definition: pdo.h:49
A PDO mapping parameter record.
Definition: pdo.h:69
co_unsigned8_t n
Number of mapped objects in PDO.
Definition: pdo.h:71
co_unsigned32_t map[0x40]
An array of objects to be mapped.
Definition: pdo.h:73
A CANopen SDO upload/download request.
Definition: sdo.h:178
A time type with nanosecond resolution.
Definition: time.h:83
can_net_t * co_tpdo_get_net(const co_tpdo_t *pdo)
Returns a pointer to the CAN network of a Transmit-PDO.
Definition: tpdo.c:335
void co_tpdo_destroy(co_tpdo_t *tpdo)
Destroys a CANopen Transmit-PDO service.
Definition: tpdo.c:325
static co_unsigned32_t co_tpdo_init_frame(co_tpdo_t *pdo, struct can_msg *msg)
Initializes a CAN frame to be sent by a Transmit-PDO service.
Definition: tpdo.c:909
static co_unsigned32_t co_1800_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen objects 1800..19FF (TPDO communicat...
Definition: tpdo.c:618
static int co_tpdo_init_recv(co_tpdo_t *pdo)
Initializes the CAN frame receiver of a Transmit-PDO service.
Definition: tpdo.c:513
int co_tpdo_event(co_tpdo_t *pdo)
Triggers the transmission of an event-driven (asynchronous) PDO.
Definition: tpdo.c:395
static int co_tpdo_init_timer_swnd(co_tpdo_t *pdo)
Initializes the CAN timer for the synchronous time window of a Transmit-PDO service.
Definition: tpdo.c:571
static int co_tpdo_timer_swnd(const struct timespec *tp, void *data)
The CAN timer callback function for the synchronous time window of a Transmit-PDO service.
Definition: tpdo.c:894
static int co_tpdo_init_buf(co_tpdo_t *pdo)
Initializes the CAN frame buffer of a Transmit-PDO service.
Definition: tpdo.c:598
const struct co_pdo_map_par * co_tpdo_get_map_par(const co_tpdo_t *pdo)
Returns a pointer to the PDO mapping parameter record of a Transmit-PDO.
Definition: tpdo.c:367
static int co_tpdo_timer_event(const struct timespec *tp, void *data)
The CAN timer callback function for events of a Transmit-PDO service.
Definition: tpdo.c:882
const struct co_pdo_comm_par * co_tpdo_get_comm_par(const co_tpdo_t *pdo)
Returns a pointer to the PDO communication parameter record of a Transmit-PDO.
Definition: tpdo.c:359
co_tpdo_t * co_tpdo_create(can_net_t *net, co_dev_t *dev, co_unsigned16_t num)
Creates a new CANopen Transmit-PDO service.
Definition: tpdo.c:298
void co_tpdo_get_next(const co_tpdo_t *pdo, struct timespec *tp)
Retrieves the time at which the next event-driven TPDO may be sent.
Definition: tpdo.c:504
void co_tpdo_get_ind(const co_tpdo_t *pdo, co_tpdo_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a Transmit-PDO error occurs.
Definition: tpdo.c:375
static int co_tpdo_recv(const struct can_msg *msg, void *data)
The CAN receive callback function for a Transmit-PDO service.
Definition: tpdo.c:848
void co_tpdo_set_ind(co_tpdo_t *pdo, co_tpdo_ind_t *ind, void *data)
Sets the indication function invoked when a Transmit-PDO error occurs.
Definition: tpdo.c:386
static co_unsigned32_t co_1a00_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen objects 1A00..1BFF (TPDO mapping pa...
Definition: tpdo.c:765
int co_tpdo_sync(co_tpdo_t *pdo, co_unsigned8_t cnt)
Triggers the transmission of a synchronous PDO.
Definition: tpdo.c:436
co_dev_t * co_tpdo_get_dev(const co_tpdo_t *pdo)
Returns a pointer to the CANopen device of a Transmit-PDO.
Definition: tpdo.c:343
co_unsigned16_t co_tpdo_get_num(const co_tpdo_t *pdo)
Returns the PDO number of a Transmit-PDO.
Definition: tpdo.c:351
static int co_tpdo_init_timer_event(co_tpdo_t *pdo)
Initializes the CAN timer for events of a Transmit-PDO service.
Definition: tpdo.c:546
This header file is part of the CANopen library; it contains the Transmit-PDO declarations.
void co_tpdo_ind_t(co_tpdo_t *pdo, co_unsigned32_t ac, const void *ptr, size_t n, void *data)
The type of a CANopen Transmit-PDO indication function, invoked when a PDO is sent or an error occurs...
Definition: tpdo.h:45
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition: type.h:47
#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:163
This header file is part of the utilities library; it contains the time function declarations.
int timespec_cmp(const void *p1, const void *p2)
Compares two times.
Definition: time.h:224
void timespec_add_usec(struct timespec *tp, uint_least64_t usec)
Adds usec microseconds to the time at tp.
Definition: time.h:138
This header file is part of the CANopen library; it contains the CANopen value declarations.
void co_val_fini(co_unsigned16_t type, void *val)
Finalizes a value of the specified data type.
Definition: val.c:273