Lely core libraries 1.9.2
ssdo.c
Go to the documentation of this file.
1
24#include "co.h"
25#include "sdo.h"
26#include <lely/co/crc.h>
27#include <lely/co/dev.h>
28#include <lely/co/obj.h>
29#include <lely/co/ssdo.h>
30#include <lely/co/val.h>
31#include <lely/util/endian.h>
32#include <lely/util/errnum.h>
33
34#include <assert.h>
35#include <inttypes.h>
36#include <stdlib.h>
37
38struct __co_ssdo_state;
40typedef const struct __co_ssdo_state co_ssdo_state_t;
41
43struct __co_ssdo {
49 co_unsigned8_t num;
61 co_unsigned16_t idx;
63 co_unsigned8_t subidx;
65 uint8_t toggle;
67 uint8_t blksize;
69 uint8_t ackseq;
71 unsigned gencrc : 1;
73 uint16_t crc;
77 struct membuf buf;
79 size_t nbyte;
80};
81
88static int co_ssdo_update(co_ssdo_t *sdo);
89
96static co_unsigned32_t co_1200_dn_ind(
97 co_sub_t *sub, struct co_sdo_req *req, void *data);
98
104static int co_ssdo_recv(const struct can_msg *msg, void *data);
105
111static int co_ssdo_timer(const struct timespec *tp, void *data);
112
114static inline void co_ssdo_enter(co_ssdo_t *sdo, co_ssdo_state_t *next);
115
123static inline void co_ssdo_emit_abort(co_ssdo_t *sdo, co_unsigned32_t ac);
124
132static inline void co_ssdo_emit_time(co_ssdo_t *sdo, const struct timespec *tp);
133
141static inline void co_ssdo_emit_recv(co_ssdo_t *sdo, const struct can_msg *msg);
142
154 co_ssdo_state_t *(*on_abort)(co_ssdo_t *sdo, co_unsigned32_t ac);
163 co_ssdo_state_t *(*on_time)(co_ssdo_t *sdo, const struct timespec *tp);
173 co_ssdo_state_t *(*on_recv)(co_ssdo_t *sdo, const struct can_msg *msg);
174};
175
176#define LELY_CO_DEFINE_STATE(name, ...) \
177 static co_ssdo_state_t *const name = &(co_ssdo_state_t){ __VA_ARGS__ };
178
181 co_ssdo_t *sdo, co_unsigned32_t ac);
182
185 co_ssdo_t *sdo, const struct can_msg *msg);
186
188// clang-format off
189LELY_CO_DEFINE_STATE(co_ssdo_wait_state,
190 .on_abort = &co_ssdo_wait_on_abort,
191 .on_recv = &co_ssdo_wait_on_recv
193// clang-format on
194
195
200 co_ssdo_t *sdo, const struct can_msg *msg);
201
203// LELY_CO_DEFINE_STATE(co_ssdo_dn_ini_state,
204// .on_recv = &co_ssdo_dn_ini_on_recv
205//)
206
209 co_ssdo_t *sdo, co_unsigned32_t ac);
210
213 co_ssdo_t *sdo, const struct timespec *tp);
214
219 co_ssdo_t *sdo, const struct can_msg *msg);
220
222// clang-format off
223LELY_CO_DEFINE_STATE(co_ssdo_dn_seg_state,
224 .on_abort = &co_ssdo_dn_seg_on_abort,
225 .on_time = &co_ssdo_dn_seg_on_time,
226 .on_recv = &co_ssdo_dn_seg_on_recv
228// clang-format on
229
232 co_ssdo_t *sdo, const struct can_msg *msg);
233
235// LELY_CO_DEFINE_STATE(co_ssdo_up_ini_state,
236// .on_recv = &co_ssdo_up_ini_on_recv
237//)
238
241 co_ssdo_t *sdo, co_unsigned32_t ac);
242
245 co_ssdo_t *sdo, const struct timespec *tp);
246
249 co_ssdo_t *sdo, const struct can_msg *msg);
250
252// clang-format off
253LELY_CO_DEFINE_STATE(co_ssdo_up_seg_state,
254 .on_abort = &co_ssdo_up_seg_on_abort,
255 .on_time = &co_ssdo_up_seg_on_time,
256 .on_recv = &co_ssdo_up_seg_on_recv
258// clang-format on
259
265 co_ssdo_t *sdo, const struct can_msg *msg);
266
268// LELY_CO_DEFINE_STATE(co_ssdo_blk_dn_ini_state,
269// .on_recv = &co_ssdo_blk_dn_ini_on_recv
270//)
271
274 co_ssdo_t *sdo, co_unsigned32_t ac);
275
278 co_ssdo_t *sdo, const struct timespec *tp);
279
285 co_ssdo_t *sdo, const struct can_msg *msg);
286
288// clang-format off
289LELY_CO_DEFINE_STATE(co_ssdo_blk_dn_sub_state,
290 .on_abort = &co_ssdo_blk_dn_sub_on_abort,
291 .on_time = &co_ssdo_blk_dn_sub_on_time,
294// clang-format on
295
298 co_ssdo_t *sdo, co_unsigned32_t ac);
299
302 co_ssdo_t *sdo, const struct timespec *tp);
303
309 co_ssdo_t *sdo, const struct can_msg *msg);
310
312// clang-format off
313LELY_CO_DEFINE_STATE(co_ssdo_blk_dn_end_state,
314 .on_abort = &co_ssdo_blk_dn_end_on_abort,
315 .on_time = &co_ssdo_blk_dn_end_on_time,
318// clang-format on
319
325 co_ssdo_t *sdo, const struct can_msg *msg);
326
328// LELY_CO_DEFINE_STATE(co_ssdo_blk_up_ini_state,
329// .on_recv = &co_ssdo_blk_up_ini_on_recv
330//)
331
334 co_ssdo_t *sdo, co_unsigned32_t ac);
335
338 co_ssdo_t *sdo, const struct timespec *tp);
339
345 co_ssdo_t *sdo, const struct can_msg *msg);
346
348// clang-format off
349LELY_CO_DEFINE_STATE(co_ssdo_blk_up_sub_state,
350 .on_abort = &co_ssdo_blk_up_sub_on_abort,
351 .on_time = &co_ssdo_blk_up_sub_on_time,
354// clang-format on
355
358 co_ssdo_t *sdo, co_unsigned32_t ac);
359
362 co_ssdo_t *sdo, const struct timespec *tp);
363
368 co_ssdo_t *sdo, const struct can_msg *msg);
369
371// clang-format off
372LELY_CO_DEFINE_STATE(co_ssdo_blk_up_end_state,
373 .on_abort = &co_ssdo_blk_up_end_on_abort,
374 .on_time = &co_ssdo_blk_up_end_on_time,
377// clang-format on
378
379#undef LELY_CO_DEFINE_STATE
380
388
400static co_ssdo_state_t *co_ssdo_abort_res(co_ssdo_t *sdo, co_unsigned32_t ac);
401
408static co_unsigned32_t co_ssdo_dn_ind(co_ssdo_t *sdo);
409
416static co_unsigned32_t co_ssdo_up_ind(co_ssdo_t *sdo);
417
424static co_unsigned32_t co_ssdo_up_buf(co_ssdo_t *sdo, size_t nbyte);
425
432static void co_ssdo_send_abort(co_ssdo_t *sdo, co_unsigned32_t ac);
433
435static void co_ssdo_send_dn_ini_res(co_ssdo_t *sdo);
436
438static void co_ssdo_send_dn_seg_res(co_ssdo_t *sdo);
439
441static void co_ssdo_send_up_exp_res(co_ssdo_t *sdo);
442
444static void co_ssdo_send_up_ini_res(co_ssdo_t *sdo);
445
452static void co_ssdo_send_up_seg_res(co_ssdo_t *sdo, int last);
453
455static void co_ssdo_send_blk_dn_ini_res(co_ssdo_t *sdo);
456
458static void co_ssdo_send_blk_dn_sub_res(co_ssdo_t *sdo);
459
461static void co_ssdo_send_blk_dn_end_res(co_ssdo_t *sdo);
462
464static void co_ssdo_send_blk_up_ini_res(co_ssdo_t *sdo);
465
472static void co_ssdo_send_blk_up_sub_res(co_ssdo_t *sdo, int last);
473
475static void co_ssdo_send_blk_up_end_res(co_ssdo_t *sdo);
476
484static void co_ssdo_init_ini_res(
485 co_ssdo_t *sdo, struct can_msg *msg, uint8_t cs);
486
494static void co_ssdo_init_seg_res(
495 co_ssdo_t *sdo, struct can_msg *msg, uint8_t cs);
496
497void *
498__co_ssdo_alloc(void)
499{
500 void *ptr = malloc(sizeof(struct __co_ssdo));
501 if (__unlikely(!ptr))
502 set_errc(errno2c(errno));
503 return ptr;
504}
505
506void
507__co_ssdo_free(void *ptr)
508{
509 free(ptr);
510}
511
512struct __co_ssdo *
513__co_ssdo_init(struct __co_ssdo *sdo, can_net_t *net, co_dev_t *dev,
514 co_unsigned8_t num)
515{
516 assert(sdo);
517 assert(net);
518 assert(dev);
519
520 int errc = 0;
521
522 if (__unlikely(!num || num > 128)) {
523 errc = errnum2c(ERRNUM_INVAL);
524 goto error_param;
525 }
526
527 // Find the SDO server parameter in the object dictionary. The default
528 // SDO (1200) is optional.
529 co_obj_t *obj_1200 = co_dev_find_obj(dev, 0x1200 + num - 1);
530 if (__unlikely(num != 1 && !obj_1200)) {
531 errc = errnum2c(ERRNUM_INVAL);
532 goto error_param;
533 }
534
535 sdo->net = net;
536 sdo->dev = dev;
537 sdo->num = num;
538
539 // Initialize the SDO parameter record with the default values.
540 sdo->par.n = 3;
541 sdo->par.id = co_dev_get_id(dev);
542 sdo->par.cobid_req = 0x600 + sdo->par.id;
543 sdo->par.cobid_res = 0x580 + sdo->par.id;
544
545 if (obj_1200) {
546 // Copy the SDO parameter record.
547 size_t size = co_obj_sizeof_val(obj_1200);
548 memcpy(&sdo->par, co_obj_addressof_val(obj_1200),
549 MIN(size, sizeof(sdo->par)));
550 }
551
552 sdo->recv = can_recv_create();
553 if (__unlikely(!sdo->recv)) {
554 errc = get_errc();
555 goto error_create_recv;
556 }
558
559 sdo->timeout = 0;
560
561 sdo->timer = can_timer_create();
562 if (__unlikely(!sdo->timer)) {
563 errc = get_errc();
564 goto error_create_timer;
565 }
567
569
570 sdo->idx = 0;
571 sdo->subidx = 0;
572
573 sdo->toggle = 0;
574 sdo->blksize = 0;
575 sdo->ackseq = 0;
576 sdo->gencrc = 0;
577 sdo->crc = 0;
578
579 co_sdo_req_init(&sdo->req);
580 membuf_init(&sdo->buf);
581 sdo->nbyte = 0;
582
583 // Set the download indication function for the SDO parameter record.
584 if (obj_1200)
585 co_obj_set_dn_ind(obj_1200, &co_1200_dn_ind, sdo);
586
587 if (__unlikely(co_ssdo_update(sdo) == -1)) {
588 errc = get_errc();
589 goto error_update;
590 }
591
592 return sdo;
593
594error_update:
595 if (obj_1200)
596 co_obj_set_dn_ind(obj_1200, NULL, NULL);
598error_create_timer:
600error_create_recv:
601error_param:
602 set_errc(errc);
603 return NULL;
604}
605
606void
607__co_ssdo_fini(struct __co_ssdo *sdo)
608{
609 assert(sdo);
610 assert(sdo->num >= 1 && sdo->num <= 128);
611
612 // Remove the download indication functions for the SDO parameter
613 // record.
614 co_obj_t *obj_1200 = co_dev_find_obj(sdo->dev, 0x1200 + sdo->num - 1);
615 if (obj_1200)
616 co_obj_set_dn_ind(obj_1200, NULL, NULL);
617
618 // Abort any ongoing transfer.
620
621 membuf_fini(&sdo->buf);
622 co_sdo_req_fini(&sdo->req);
623
625
627}
628
629co_ssdo_t *
631{
632 trace("creating Server-SDO %d", num);
633
634 int errc = 0;
635
636 co_ssdo_t *sdo = __co_ssdo_alloc();
637 if (__unlikely(!sdo)) {
638 errc = get_errc();
639 goto error_alloc_sdo;
640 }
641
642 if (__unlikely(!__co_ssdo_init(sdo, net, dev, num))) {
643 errc = get_errc();
644 goto error_init_sdo;
645 }
646
647 return sdo;
648
649error_init_sdo:
650 __co_ssdo_free(sdo);
651error_alloc_sdo:
652 set_errc(errc);
653 return NULL;
654}
655
656void
658{
659 if (ssdo) {
660 trace("destroying Server-SDO %d", ssdo->num);
661 __co_ssdo_fini(ssdo);
662 __co_ssdo_free(ssdo);
663 }
664}
665
666can_net_t *
668{
669 assert(sdo);
670
671 return sdo->net;
672}
673
674co_dev_t *
676{
677 assert(sdo);
678
679 return sdo->dev;
680}
681
682co_unsigned8_t
684{
685 assert(sdo);
686
687 return sdo->num;
688}
689
690const struct co_sdo_par *
692{
693 assert(sdo);
694
695 return &sdo->par;
696}
697
698int
700{
701 assert(sdo);
702
703 return sdo->timeout;
704}
705
706void
708{
709 assert(sdo);
710
711 if (sdo->timeout && timeout <= 0)
712 can_timer_stop(sdo->timer);
713
714 sdo->timeout = MAX(0, timeout);
715}
716
717static int
719{
720 assert(sdo);
721
722 // Abort any ongoing transfer.
724
725 int valid_req = !(sdo->par.cobid_req & CO_SDO_COBID_VALID);
726 int valid_res = !(sdo->par.cobid_res & CO_SDO_COBID_VALID);
727 if (valid_req && valid_res) {
728 uint32_t id = sdo->par.cobid_req;
729 uint8_t flags = 0;
730 if (id & CO_SDO_COBID_FRAME) {
731 id &= CAN_MASK_EID;
732 flags |= CAN_FLAG_IDE;
733 } else {
734 id &= CAN_MASK_BID;
735 }
736 can_recv_start(sdo->recv, sdo->net, id, flags);
737 } else {
738 can_recv_stop(sdo->recv);
739 }
740
741 return 0;
742}
743
744static co_unsigned32_t
745co_1200_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
746{
747 assert(sub);
748 assert(req);
749 co_ssdo_t *sdo = data;
750 assert(sdo);
751 assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1200 + sdo->num - 1);
752
753 co_unsigned32_t ac = 0;
754
755 co_unsigned16_t type = co_sub_get_type(sub);
756 union co_val val;
757 if (__unlikely(co_sdo_req_dn_val(req, type, &val, &ac) == -1))
758 return ac;
759
760 switch (co_sub_get_subidx(sub)) {
761 case 0: ac = CO_SDO_AC_NO_WRITE; goto error;
762 case 1: {
763 assert(type == CO_DEFTYPE_UNSIGNED32);
764 co_unsigned32_t cobid = val.u32;
765 co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
766 if (cobid == cobid_old)
767 goto error;
768
769 // The CAN-ID cannot be changed when the SDO is and remains
770 // valid.
771 int valid = !(cobid & CO_SDO_COBID_VALID);
772 int valid_old = !(cobid_old & CO_SDO_COBID_VALID);
773 uint32_t canid = cobid & CAN_MASK_EID;
774 uint32_t canid_old = cobid_old & CAN_MASK_EID;
775 if (__unlikely(valid && valid_old && canid != canid_old)) {
777 goto error;
778 }
779
780 // A 29-bit CAN-ID is only valid if the frame bit is set.
781 // clang-format off
782 if (__unlikely(!(cobid & CO_SDO_COBID_FRAME)
783 && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))) {
784 // clang-format on
786 goto error;
787 }
788
789 sdo->par.cobid_req = cobid;
790 break;
791 }
792 case 2: {
793 assert(type == CO_DEFTYPE_UNSIGNED32);
794 co_unsigned32_t cobid = val.u32;
795 co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
796 if (cobid == cobid_old)
797 goto error;
798
799 // The CAN-ID cannot be changed when the SDO is and remains
800 // valid.
801 int valid = !(cobid & CO_SDO_COBID_VALID);
802 int valid_old = !(cobid_old & CO_SDO_COBID_VALID);
803 uint32_t canid = cobid & CAN_MASK_EID;
804 uint32_t canid_old = cobid_old & CAN_MASK_EID;
805 if (__unlikely(valid && valid_old && canid != canid_old)) {
807 goto error;
808 }
809
810 // A 29-bit CAN-ID is only valid if the frame bit is set.
811 // clang-format off
812 if (__unlikely(!(cobid & CO_SDO_COBID_FRAME)
813 && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))) {
814 // clang-format on
816 goto error;
817 }
818
819 sdo->par.cobid_res = cobid;
820 break;
821 }
822 case 3: {
823 assert(type == CO_DEFTYPE_UNSIGNED8);
824 co_unsigned8_t id = val.u8;
825 co_unsigned8_t id_old = co_sub_get_val_u8(sub);
826 if (id == id_old)
827 goto error;
828
829 sdo->par.id = id;
830 break;
831 }
832 default: ac = CO_SDO_AC_NO_SUB; goto error;
833 }
834
835 co_sub_dn(sub, &val);
836 co_val_fini(type, &val);
837
838 co_ssdo_update(sdo);
839 return 0;
840
841error:
842 co_val_fini(type, &val);
843 return ac;
844}
845
846static int
847co_ssdo_recv(const struct can_msg *msg, void *data)
848{
849 assert(msg);
850 co_ssdo_t *sdo = data;
851 assert(sdo);
852
853 // Ignore remote frames.
854 if (__unlikely(msg->flags & CAN_FLAG_RTR))
855 return 0;
856
857#ifndef LELY_NO_CANFD
858 // Ignore CAN FD format frames.
859 if (__unlikely(msg->flags & CAN_FLAG_EDL))
860 return 0;
861#endif
862
863 co_ssdo_emit_recv(sdo, msg);
864
865 return 0;
866}
867
868static int
869co_ssdo_timer(const struct timespec *tp, void *data)
870{
871 assert(tp);
872 co_ssdo_t *sdo = data;
873 assert(sdo);
874
875 co_ssdo_emit_time(sdo, tp);
876
877 return 0;
878}
879
880static inline void
882{
883 assert(sdo);
884
885 if (next)
886 sdo->state = next;
887}
888
889static inline void
890co_ssdo_emit_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
891{
892 assert(sdo);
893 assert(sdo->state);
894 assert(sdo->state->on_recv);
895
896 co_ssdo_enter(sdo, sdo->state->on_abort(sdo, ac));
897}
898
899static inline void
900co_ssdo_emit_time(co_ssdo_t *sdo, const struct timespec *tp)
901{
902 assert(sdo);
903 assert(sdo->state);
904 assert(sdo->state->on_time);
905
906 co_ssdo_enter(sdo, sdo->state->on_time(sdo, tp));
907}
908
909static inline void
910co_ssdo_emit_recv(co_ssdo_t *sdo, const struct can_msg *msg)
911{
912 assert(sdo);
913 assert(sdo->state);
914 assert(sdo->state->on_recv);
915
916 co_ssdo_enter(sdo, sdo->state->on_recv(sdo, msg));
917}
918
919static co_ssdo_state_t *
920co_ssdo_wait_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
921{
922 (void)sdo;
923 (void)ac;
924
925 return NULL;
926}
927
928static co_ssdo_state_t *
929co_ssdo_wait_on_recv(co_ssdo_t *sdo, const struct can_msg *msg)
930{
931 assert(sdo);
932 assert(msg);
933
934 if (__unlikely(msg->len < 1))
936 uint8_t cs = msg->data[0];
937
938 switch (cs & CO_SDO_CS_MASK) {
939 case CO_SDO_CCS_DN_INI_REQ: return co_ssdo_dn_ini_on_recv(sdo, msg);
940 case CO_SDO_CCS_UP_INI_REQ: return co_ssdo_up_ini_on_recv(sdo, msg);
943 case CO_SDO_CS_ABORT: return NULL;
944 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
945 }
946}
947
948static co_ssdo_state_t *
950{
951 assert(sdo);
952 assert(msg);
953
954 assert(msg->len > 0);
955 uint8_t cs = msg->data[0];
956
957 // Load the object index and sub-index from the CAN frame.
958 if (__unlikely(msg->len < 3))
960 sdo->idx = ldle_u16(msg->data + 1);
961 if (__unlikely(msg->len < 4))
963 sdo->subidx = msg->data[3];
964
965 trace("SSDO: %04X:%02X: received download request", sdo->idx,
966 sdo->subidx);
967
968 // Obtain the size from the command specifier.
969 co_sdo_req_clear(&sdo->req);
970 int exp = !!(cs & CO_SDO_INI_SIZE_EXP);
971 if (exp) {
972 if (cs & CO_SDO_INI_SIZE_IND)
974 else
975 sdo->req.size = msg->len - 4;
976 } else if (cs & CO_SDO_INI_SIZE_IND) {
977 if (__unlikely(msg->len < 8))
979 sdo->req.size = ldle_u32(msg->data + 4);
980 }
981
982 if (exp) {
983 // Perform an expedited transfer.
984 sdo->req.buf = msg->data + 4;
985 sdo->req.nbyte = sdo->req.size;
986 co_unsigned32_t ac = co_ssdo_dn_ind(sdo);
987 if (__unlikely(ac))
988 return co_ssdo_abort_res(sdo, ac);
989 // Finalize the transfer.
991 return co_ssdo_abort_ind(sdo);
992 } else {
994 if (sdo->timeout)
995 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
997 }
998}
999
1000static co_ssdo_state_t *
1001co_ssdo_dn_seg_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
1002{
1003 return co_ssdo_abort_res(sdo, ac);
1004}
1005
1006static co_ssdo_state_t *
1008{
1009 (void)tp;
1010
1012}
1013
1014static co_ssdo_state_t *
1016{
1017 assert(sdo);
1018 assert(msg);
1019
1020 if (__unlikely(msg->len < 1))
1022 uint8_t cs = msg->data[0];
1023
1024 // Check the client command specifier.
1025 switch (cs & CO_SDO_CS_MASK) {
1026 case CO_SDO_CCS_DN_SEG_REQ: break;
1027 case CO_SDO_CS_ABORT: return co_ssdo_abort_ind(sdo);
1028 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1029 }
1030
1031 // Check the value of the toggle bit.
1032 if (__unlikely((cs & CO_SDO_SEG_TOGGLE) != sdo->toggle))
1033 return co_ssdo_dn_seg_state;
1034
1035 // Obtain the size of the segment.
1036 size_t n = CO_SDO_SEG_SIZE_GET(cs);
1037 if (__unlikely(msg->len < 1 + n))
1039 int last = !!(cs & CO_SDO_SEG_LAST);
1040
1041 sdo->req.buf = msg->data + 1;
1042 sdo->req.offset += sdo->req.nbyte;
1043 sdo->req.nbyte = n;
1044
1045 if (__unlikely(last && !co_sdo_req_last(&sdo->req)))
1047
1048 co_unsigned32_t ac = co_ssdo_dn_ind(sdo);
1049 if (__unlikely(ac))
1050 return co_ssdo_abort_res(sdo, ac);
1051
1053
1054 if (last) {
1055 return co_ssdo_abort_ind(sdo);
1056 } else {
1057 if (sdo->timeout)
1058 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1059 return co_ssdo_dn_seg_state;
1060 }
1061}
1062
1063static co_ssdo_state_t *
1065{
1066 assert(sdo);
1067 assert(msg);
1068
1069 // Load the object index and sub-index from the CAN frame.
1070 if (__unlikely(msg->len < 3))
1072 sdo->idx = ldle_u16(msg->data + 1);
1073 if (__unlikely(msg->len < 4))
1075 sdo->subidx = msg->data[3];
1076
1077 trace("SSDO: %04X:%02X: received upload request", sdo->idx,
1078 sdo->subidx);
1079
1080 // Perform access checks and start serializing the value.
1081 co_sdo_req_clear(&sdo->req);
1082 co_unsigned32_t ac = co_ssdo_up_ind(sdo);
1083 if (__unlikely(ac))
1084 return co_ssdo_abort_res(sdo, ac);
1085
1086 if (sdo->req.size && sdo->req.size <= 4) {
1087 // Perform an expedited transfer.
1088 if (__unlikely((ac = co_ssdo_up_buf(sdo, sdo->req.size)) != 0))
1089 return co_ssdo_abort_res(sdo, ac);
1091 return co_ssdo_abort_ind(sdo);
1092 } else {
1094 if (sdo->timeout)
1095 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1096 return co_ssdo_up_seg_state;
1097 }
1098}
1099
1100static co_ssdo_state_t *
1101co_ssdo_up_seg_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
1102{
1103 return co_ssdo_abort_res(sdo, ac);
1104}
1105
1106static co_ssdo_state_t *
1108{
1109 (void)tp;
1110
1112}
1113
1114static co_ssdo_state_t *
1116{
1117 assert(sdo);
1118 assert(msg);
1119
1120 if (__unlikely(msg->len < 1))
1122 uint8_t cs = msg->data[0];
1123
1124 // Check the client command specifier.
1125 switch (cs & CO_SDO_CS_MASK) {
1126 case CO_SDO_CCS_UP_SEG_REQ: break;
1127 case CO_SDO_CS_ABORT: return co_ssdo_abort_ind(sdo);
1128 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1129 }
1130
1131 // Check the value of the toggle bit.
1132 if (__unlikely((cs & CO_SDO_SEG_TOGGLE) != sdo->toggle))
1134
1135 membuf_clear(&sdo->buf);
1136 co_unsigned32_t ac = co_ssdo_up_buf(sdo, 7);
1137 if (__unlikely(ac))
1138 return co_ssdo_abort_res(sdo, ac);
1139
1140 int last = co_sdo_req_last(&sdo->req) && sdo->nbyte == sdo->req.nbyte;
1141 co_ssdo_send_up_seg_res(sdo, last);
1142
1143 if (last) {
1144 // Finalize the transfer.
1145 return co_ssdo_abort_ind(sdo);
1146 } else {
1147 if (sdo->timeout)
1148 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1149 return co_ssdo_up_seg_state;
1150 }
1151}
1152
1153static co_ssdo_state_t *
1155{
1156 assert(sdo);
1157 assert(msg);
1158
1159 assert(msg->len > 0);
1160 uint8_t cs = msg->data[0];
1161
1162 // Check the client subcommand.
1163 if (__unlikely((cs & 0x01) != CO_SDO_SC_INI_BLK))
1165
1166 // Check if the client supports generating a CRC.
1167 sdo->gencrc = !!(cs & CO_SDO_BLK_CRC);
1168
1169 // Load the object index and sub-index from the CAN frame.
1170 if (__unlikely(msg->len < 3))
1172 sdo->idx = ldle_u16(msg->data + 1);
1173 if (__unlikely(msg->len < 4))
1175 sdo->subidx = msg->data[3];
1176
1177 trace("SSDO: %04X:%02X: received block download request", sdo->idx,
1178 sdo->subidx);
1179
1180 // Obtain the data set size.
1181 co_sdo_req_clear(&sdo->req);
1182 if (cs & CO_SDO_BLK_SIZE_IND) {
1183 if (__unlikely(msg->len < 8))
1185 sdo->req.size = ldle_u32(msg->data + 4);
1186 }
1187
1188 // Use the maximum block size by default.
1190 sdo->ackseq = 0;
1191
1193
1194 if (sdo->timeout)
1195 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1197}
1198
1199static co_ssdo_state_t *
1201{
1202 return co_ssdo_abort_res(sdo, ac);
1203}
1204
1205static co_ssdo_state_t *
1207{
1208 (void)tp;
1209
1211}
1212
1213static co_ssdo_state_t *
1215{
1216 assert(sdo);
1217 assert(msg);
1218
1219 if (__unlikely(msg->len < 1))
1221 uint8_t cs = msg->data[0];
1222
1223 if (__unlikely(cs == CO_SDO_CS_ABORT))
1224 return co_ssdo_abort_ind(sdo);
1225
1226 uint8_t seqno = cs & ~CO_SDO_SEQ_LAST;
1227 int last = !!(cs & CO_SDO_SEQ_LAST);
1228
1229 if (__unlikely(!seqno || seqno > sdo->blksize))
1231
1232 // Only accept sequential segments. Dropped segments will be resent
1233 // after the confirmation message.
1234 if (seqno == sdo->ackseq + 1) {
1235 sdo->ackseq++;
1236 // Update the CRC.
1237 if (sdo->gencrc)
1238 sdo->crc = co_crc(
1239 sdo->crc, sdo->req.buf, sdo->req.nbyte);
1240 // Pass the previous frame to the download indication function.
1241 co_unsigned32_t ac = co_ssdo_dn_ind(sdo);
1242 if (__unlikely(ac))
1243 return co_ssdo_abort_res(sdo, ac);
1244 // Copy the new frame to the SDO request.
1245 membuf_clear(&sdo->buf);
1246 if (__unlikely(!membuf_reserve(&sdo->buf, 7)))
1248 membuf_write(&sdo->buf, msg->data + 1, 7);
1249 sdo->req.buf = membuf_begin(&sdo->buf);
1250 sdo->req.offset += sdo->req.nbyte;
1251 sdo->req.nbyte = membuf_size(&sdo->buf);
1252 }
1253
1254 // If this is the last segment in the block, send a confirmation.
1255 if (seqno == sdo->blksize || last) {
1257 sdo->ackseq = 0;
1258 }
1259
1260 if (sdo->timeout)
1261 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1263}
1264
1265static co_ssdo_state_t *
1267{
1268 return co_ssdo_abort_res(sdo, ac);
1269}
1270
1271static co_ssdo_state_t *
1273{
1274 (void)tp;
1275
1277}
1278
1279static co_ssdo_state_t *
1281{
1282 assert(sdo);
1283 assert(msg);
1284
1285 if (__unlikely(msg->len < 1))
1287 uint8_t cs = msg->data[0];
1288
1289 // Check the client command specifier.
1290 switch (cs & CO_SDO_CS_MASK) {
1291 case CO_SDO_CCS_BLK_DN_REQ: break;
1292 case CO_SDO_CS_ABORT: return co_ssdo_abort_ind(sdo);
1293 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1294 }
1295
1296 // Check the client subcommand.
1299
1300 // Discard the bytes in the last segment that did not contain data.
1301 sdo->req.nbyte -= 7 - CO_SDO_BLK_SIZE_GET(cs);
1302
1303 // Check the CRC.
1304 if (sdo->gencrc) {
1305 sdo->crc = co_crc(sdo->crc, sdo->req.buf, sdo->req.nbyte);
1306 uint16_t crc = ldle_u16(msg->data + 1);
1307 if (__unlikely(sdo->crc != crc))
1309 }
1310
1311 co_unsigned32_t ac = co_ssdo_dn_ind(sdo);
1312 if (__unlikely(ac))
1313 return co_ssdo_abort_res(sdo, ac);
1314
1315 // Finalize the transfer.
1317 return co_ssdo_abort_ind(sdo);
1318}
1319
1320static co_ssdo_state_t *
1322{
1323 assert(sdo);
1324 assert(msg);
1325
1326 assert(msg->len > 0);
1327 uint8_t cs = msg->data[0];
1328
1329 // Check the client subcommand.
1332
1333 // Check if the client supports generating a CRC.
1334 sdo->gencrc = !!(cs & CO_SDO_BLK_CRC);
1335
1336 // Load the object index and sub-index from the CAN frame.
1337 if (__unlikely(msg->len < 3))
1339 sdo->idx = ldle_u16(msg->data + 1);
1340 if (__unlikely(msg->len < 4))
1342 sdo->subidx = msg->data[3];
1343
1344 trace("SSDO: %04X:%02X: received block upload request", sdo->idx,
1345 sdo->subidx);
1346
1347 // Load the number of segments per block.
1348 if (__unlikely(msg->len < 5))
1350 sdo->blksize = msg->data[4];
1351 if (__unlikely(!sdo->blksize || sdo->blksize > CO_SDO_MAX_SEQNO))
1353
1354 // Load the protocol switch threshold (PST).
1355 uint8_t pst = msg->len > 5 ? msg->data[5] : 0;
1356
1357 // Perform access checks and start serializing the value.
1358 co_sdo_req_clear(&sdo->req);
1359 co_unsigned32_t ac = co_ssdo_up_ind(sdo);
1360 if (__unlikely(ac))
1361 return co_ssdo_abort_res(sdo, ac);
1362
1363 if (pst && sdo->req.size <= pst) {
1364 // If the PST is non-zero, and the number of bytes is smaller
1365 // than or equal to the PST, switch to the SDO upload protocol.
1366 if (sdo->req.size <= 4) {
1367 // Perform an expedited transfer.
1368 // clang-format off
1369 if (__unlikely((ac = co_ssdo_up_buf(sdo, sdo->req.size))
1370 != 0))
1371 // clang-format on
1372 return co_ssdo_abort_res(sdo, ac);
1374 return co_ssdo_abort_ind(sdo);
1375 } else {
1377 if (sdo->timeout)
1378 can_timer_timeout(sdo->timer, sdo->net,
1379 sdo->timeout);
1380 return co_ssdo_up_seg_state;
1381 }
1382 } else {
1384 if (sdo->timeout)
1385 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1387 }
1388}
1389
1390static co_ssdo_state_t *
1392{
1393 return co_ssdo_abort_res(sdo, ac);
1394}
1395
1396static co_ssdo_state_t *
1398{
1399 (void)tp;
1400
1402}
1403
1404static co_ssdo_state_t *
1406{
1407 assert(sdo);
1408 assert(msg);
1409
1410 if (__unlikely(msg->len < 1))
1412 uint8_t cs = msg->data[0];
1413
1414 // Check the client command specifier.
1415 switch (cs & CO_SDO_CS_MASK) {
1416 case CO_SDO_CCS_BLK_UP_REQ: break;
1417 case CO_SDO_CS_ABORT: return co_ssdo_abort_ind(sdo);
1418 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1419 }
1420
1421 // Check the client subcommand.
1422 switch (cs & CO_SDO_SC_MASK) {
1423 case CO_SDO_SC_BLK_RES:
1424 if (__unlikely(co_sdo_req_first(&sdo->req) && !sdo->nbyte))
1426
1427 if (__unlikely(msg->len < 3))
1429
1430 // Flush the successfully sent segments from the buffer.
1431 uint8_t ackseq = msg->data[1];
1432 membuf_flush(&sdo->buf, ackseq * 7);
1433
1434 // Read the number of segments in the next block.
1435 sdo->blksize = msg->data[2];
1436 // clang-format off
1437 if (__unlikely(!sdo->blksize
1438 || sdo->blksize > CO_SDO_MAX_SEQNO))
1439 // clang-format on
1441
1442 break;
1443 case CO_SDO_SC_START_UP:
1444 if (__unlikely(!(co_sdo_req_first(&sdo->req) && !sdo->nbyte)))
1446 break;
1447 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1448 }
1449
1450 ptrdiff_t n = sdo->blksize * 7 - membuf_size(&sdo->buf);
1451 if (n > 0) {
1452 if (__unlikely(!membuf_reserve(&sdo->buf, n)))
1454 co_unsigned32_t ac = co_ssdo_up_buf(sdo, n);
1455 if (__unlikely(ac))
1456 return co_ssdo_abort_res(sdo, ac);
1457 sdo->blksize = (uint8_t)((membuf_size(&sdo->buf) + 6) / 7);
1458 }
1459 int last = co_sdo_req_last(&sdo->req) && sdo->nbyte == sdo->req.nbyte;
1460
1461 if (sdo->timeout)
1462 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1463
1464 if (sdo->blksize) {
1465 // Send all segments in the current block.
1466 co_ssdo_send_blk_up_sub_res(sdo, last);
1468 } else {
1471 }
1472}
1473
1474static co_ssdo_state_t *
1476{
1477 return co_ssdo_abort_res(sdo, ac);
1478}
1479
1480static co_ssdo_state_t *
1482{
1483 (void)tp;
1484
1486}
1487
1488static co_ssdo_state_t *
1490{
1491 assert(sdo);
1492 assert(msg);
1493
1494 if (__unlikely(msg->len < 1))
1496 uint8_t cs = msg->data[0];
1497
1498 // Check the client command specifier.
1499 switch (cs & CO_SDO_CS_MASK) {
1500 case CO_SDO_CCS_BLK_UP_REQ: break;
1501 case CO_SDO_CS_ABORT: return co_ssdo_abort_ind(sdo);
1502 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1503 }
1504
1505 // Check the client subcommand.
1508
1509 return co_ssdo_abort_ind(sdo);
1510}
1511
1512static co_ssdo_state_t *
1514{
1515 assert(sdo);
1516
1517 if (sdo->timeout)
1518 can_timer_stop(sdo->timer);
1519
1520 sdo->idx = 0;
1521 sdo->subidx = 0;
1522
1523 sdo->toggle = 0;
1524 sdo->blksize = 0;
1525 sdo->ackseq = 0;
1526 sdo->gencrc = 0;
1527 sdo->crc = 0;
1528
1529 co_sdo_req_clear(&sdo->req);
1530 membuf_clear(&sdo->buf);
1531 sdo->nbyte = 0;
1532
1533 return co_ssdo_wait_state;
1534}
1535
1536static co_ssdo_state_t *
1537co_ssdo_abort_res(co_ssdo_t *sdo, co_unsigned32_t ac)
1538{
1539 trace("SSDO: abort code %08" PRIX32 " (%s)", ac, co_sdo_ac2str(ac));
1540 co_ssdo_send_abort(sdo, ac);
1541 return co_ssdo_abort_ind(sdo);
1542}
1543
1544static co_unsigned32_t
1546{
1547 assert(sdo);
1548
1549 // Find the object in the object dictionary.
1550 co_obj_t *obj = co_dev_find_obj(sdo->dev, sdo->idx);
1551 if (__unlikely(!obj))
1552 return CO_SDO_AC_NO_OBJ;
1553
1554 // Find the sub-object.
1555 co_sub_t *sub = co_obj_find_sub(obj, sdo->subidx);
1556 if (__unlikely(!sub))
1557 return CO_SDO_AC_NO_SUB;
1558
1559 return co_sub_dn_ind(sub, &sdo->req);
1560}
1561
1562static co_unsigned32_t
1564{
1565 assert(sdo);
1566
1567 // Find the object in the object dictionary.
1568 const co_obj_t *obj = co_dev_find_obj(sdo->dev, sdo->idx);
1569 if (__unlikely(!obj))
1570 return CO_SDO_AC_NO_OBJ;
1571
1572 // Find the sub-object.
1573 const co_sub_t *sub = co_obj_find_sub(obj, sdo->subidx);
1574 if (__unlikely(!sub))
1575 return CO_SDO_AC_NO_SUB;
1576
1577 // If the object is an array, check whether the element exists.
1578 // clang-format off
1580 > co_obj_get_val_u8(obj, 0x00)))
1581 // clang-format on
1582 return CO_SDO_AC_NO_DATA;
1583
1584 sdo->nbyte = 0;
1585 return co_sub_up_ind(sub, &sdo->req);
1586}
1587
1588static co_unsigned32_t
1589co_ssdo_up_buf(co_ssdo_t *sdo, size_t nbyte)
1590{
1591 co_unsigned32_t ac = 0;
1592
1593 if (__unlikely(nbyte && !membuf_reserve(&sdo->buf, nbyte)))
1594 return CO_SDO_AC_NO_MEM;
1595
1596 while (nbyte) {
1597 if (sdo->nbyte >= sdo->req.nbyte) {
1598 if (co_sdo_req_last(&sdo->req)
1599 || __unlikely(ac = co_ssdo_up_ind(sdo)))
1600 break;
1601 sdo->nbyte = 0;
1602 }
1603 const char *src = (const char *)sdo->req.buf + sdo->nbyte;
1604 size_t n = MIN(nbyte, sdo->req.nbyte - sdo->nbyte);
1605
1606 if (sdo->gencrc)
1607 sdo->crc = co_crc(sdo->crc, src, n);
1608
1609 membuf_write(&sdo->buf, src, n);
1610 nbyte -= n;
1611 sdo->nbyte += n;
1612 }
1613
1614 return ac;
1615}
1616
1617static void
1618co_ssdo_send_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
1619{
1620 assert(sdo);
1621
1622 struct can_msg msg;
1624 stle_u32(msg.data + 4, ac);
1625 can_net_send(sdo->net, &msg);
1626}
1627
1628static void
1630{
1631 assert(sdo);
1632
1633 uint8_t cs = CO_SDO_SCS_DN_INI_RES;
1634
1635 struct can_msg msg;
1636 co_ssdo_init_ini_res(sdo, &msg, cs);
1637 can_net_send(sdo->net, &msg);
1638}
1639
1640static void
1642{
1643 assert(sdo);
1644
1645 uint8_t cs = CO_SDO_SCS_DN_SEG_RES | sdo->toggle;
1646 sdo->toggle ^= CO_SDO_SEG_TOGGLE;
1647
1648 struct can_msg msg;
1649 co_ssdo_init_seg_res(sdo, &msg, cs);
1650 can_net_send(sdo->net, &msg);
1651}
1652
1653static void
1655{
1656 assert(sdo);
1657 assert(sdo->req.size && sdo->req.size <= 4);
1658
1659 const char *buf = membuf_begin(&sdo->buf);
1660 size_t nbyte = membuf_size(&sdo->buf);
1661 assert(nbyte == sdo->req.size);
1662
1663 uint8_t cs = CO_SDO_SCS_UP_INI_RES | CO_SDO_INI_SIZE_EXP_SET(nbyte);
1664
1665 struct can_msg msg;
1666 co_ssdo_init_ini_res(sdo, &msg, cs);
1667 memcpy(msg.data + 4, buf, nbyte);
1668 can_net_send(sdo->net, &msg);
1669}
1670
1671static void
1673{
1674 assert(sdo);
1675 assert(!sdo->req.size || sdo->req.size > 4);
1676
1678
1679 struct can_msg msg;
1680 co_ssdo_init_ini_res(sdo, &msg, cs);
1681 stle_u32(msg.data + 4, sdo->req.size);
1682 can_net_send(sdo->net, &msg);
1683}
1684
1685static void
1687{
1688 assert(sdo);
1689 assert(!sdo->req.size || sdo->req.size > 4);
1690
1691 const char *buf = membuf_begin(&sdo->buf);
1692 size_t nbyte = membuf_size(&sdo->buf);
1693 assert(nbyte <= 7);
1694
1695 uint8_t cs = CO_SDO_SCS_UP_SEG_RES | sdo->toggle
1696 | CO_SDO_SEG_SIZE_SET(nbyte);
1697 sdo->toggle ^= CO_SDO_SEG_TOGGLE;
1698 if (last)
1699 cs |= CO_SDO_SEG_LAST;
1700
1701 struct can_msg msg;
1702 co_ssdo_init_seg_res(sdo, &msg, cs);
1703 memcpy(msg.data + 1, buf, nbyte);
1704 can_net_send(sdo->net, &msg);
1705}
1706
1707static void
1709{
1710 assert(sdo);
1711
1713
1714 struct can_msg msg;
1715 co_ssdo_init_ini_res(sdo, &msg, cs);
1716 msg.data[4] = sdo->blksize;
1717 can_net_send(sdo->net, &msg);
1718}
1719
1720static void
1722{
1723 assert(sdo);
1724
1726
1727 struct can_msg msg;
1728 co_ssdo_init_seg_res(sdo, &msg, cs);
1729 msg.data[1] = sdo->ackseq;
1730 msg.data[2] = sdo->blksize;
1731 can_net_send(sdo->net, &msg);
1732}
1733
1734static void
1736{
1737 assert(sdo);
1738
1740
1741 struct can_msg msg;
1742 co_ssdo_init_seg_res(sdo, &msg, cs);
1743 can_net_send(sdo->net, &msg);
1744}
1745
1746static void
1748{
1749 assert(sdo);
1750
1753
1754 struct can_msg msg;
1755 co_ssdo_init_ini_res(sdo, &msg, cs);
1756 stle_u32(msg.data + 4, sdo->req.size);
1757 can_net_send(sdo->net, &msg);
1758}
1759
1760static void
1762{
1763 assert(sdo);
1764
1765 const char *buf = membuf_begin(&sdo->buf);
1766 size_t nbyte = membuf_size(&sdo->buf);
1767
1768 for (uint8_t seqno = 1; seqno <= sdo->blksize;
1769 seqno++, buf += 7, nbyte -= 7) {
1770 uint8_t cs = seqno;
1771 if (last && nbyte <= 7)
1772 cs |= CO_SDO_SEQ_LAST;
1773
1774 struct can_msg msg;
1775 co_ssdo_init_seg_res(sdo, &msg, cs);
1776 memcpy(msg.data + 1, buf, MIN(nbyte, 7));
1777 can_net_send(sdo->net, &msg);
1778 }
1779}
1780
1781static void
1783{
1784 assert(sdo);
1785
1786 // Compute the number of bytes in the last segment containing data.
1787 uint8_t n = sdo->req.size ? (sdo->req.size - 1) % 7 + 1 : 0;
1788
1791
1792 struct can_msg msg;
1793 co_ssdo_init_seg_res(sdo, &msg, cs);
1794 stle_u16(msg.data + 1, sdo->crc);
1795 can_net_send(sdo->net, &msg);
1796}
1797
1798static void
1799co_ssdo_init_ini_res(co_ssdo_t *sdo, struct can_msg *msg, uint8_t cs)
1800{
1801 assert(sdo);
1802 assert(msg);
1803
1804 *msg = (struct can_msg)CAN_MSG_INIT;
1805 msg->id = sdo->par.cobid_res;
1806 if (sdo->par.cobid_res & CO_SDO_COBID_FRAME) {
1807 msg->id &= CAN_MASK_EID;
1808 msg->flags |= CAN_FLAG_IDE;
1809 } else {
1810 msg->id &= CAN_MASK_BID;
1811 }
1812 msg->len = CAN_MAX_LEN;
1813 msg->data[0] = cs;
1814 stle_u16(msg->data + 1, sdo->idx);
1815 msg->data[3] = sdo->subidx;
1816}
1817
1818static void
1819co_ssdo_init_seg_res(co_ssdo_t *sdo, struct can_msg *msg, uint8_t cs)
1820{
1821 assert(sdo);
1822 assert(msg);
1823
1824 *msg = (struct can_msg)CAN_MSG_INIT;
1825 msg->id = sdo->par.cobid_res;
1826 if (sdo->par.cobid_res & CO_SDO_COBID_FRAME) {
1827 msg->id &= CAN_MASK_EID;
1828 msg->flags |= CAN_FLAG_IDE;
1829 } else {
1830 msg->id &= CAN_MASK_BID;
1831 }
1832 msg->len = CAN_MAX_LEN;
1833 msg->data[0] = cs;
1834}
This header file is part of the CANopen library; it contains the Cyclic Redundancy Check (CRC) declar...
uint16_t co_crc(uint16_t crc, const void *ptr, size_t n)
Computes a CRC-16 checksum.
Definition: crc.c:28
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
co_unsigned8_t co_dev_get_id(const co_dev_t *dev)
Returns the node-ID of a CANopen device.
Definition: dev.c:198
This header file is part of the utilities library; it contains the byte order (endianness) function d...
void stle_u16(void *ptr, uint_least16_t x)
Stores a 16-bit unsigned integer in little-endian byte order.
Definition: endian.h:480
void stle_u32(void *ptr, uint_least32_t x)
Stores a 32-bit unsigned integer in little-endian byte order.
Definition: endian.h:534
uint_least32_t ldle_u32(const void *ptr)
Loads a 32-bit unsigned integer in little-endian byte order.
Definition: endian.h:541
uint_least16_t ldle_u16(const void *ptr)
Loads a 16-bit unsigned integer in little-endian byte order.
Definition: endian.h:487
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
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
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
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
co_unsigned32_t co_sub_dn_ind(co_sub_t *sub, struct co_sdo_req *req)
Invokes the download indication function of a CANopen sub-object, registered with co_sub_set_dn_ind()...
Definition: obj.c:794
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
co_unsigned32_t co_sub_up_ind(const co_sub_t *sub, struct co_sdo_req *req)
Invokes the upload indication function of a CANopen sub-object, registered with co_sub_set_up_ind().
Definition: obj.c:890
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:207
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
co_unsigned8_t co_obj_get_code(const co_obj_t *obj)
Returns the object code of a CANopen object.
Definition: obj.c:250
#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
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
int co_sdo_req_first(const struct co_sdo_req *req)
Returns 1 if the specified request includes the first segment, and 0 otherwise.
Definition: sdo.h:340
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
#define CO_SDO_AC_TOGGLE
SDO abort code: Toggle bit not altered.
Definition: sdo.h:63
#define CO_SDO_AC_NO_CS
SDO abort code: Client/server command specifier not valid or unknown.
Definition: sdo.h:69
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_TYPE_LEN
SDO abort code: Data type does not match, length of service parameter does not match.
Definition: sdo.h:117
#define CO_SDO_AC_BLK_SEQ
SDO abort code: Invalid sequence number (block mode only).
Definition: sdo.h:75
#define CO_SDO_AC_NO_SDO
SDO abort code: Resource not available: SDO connection.
Definition: sdo.h:147
#define CO_SDO_AC_NO_OBJ
SDO abort code: Object does not exist in the object dictionary.
Definition: sdo.h:93
#define CO_SDO_COBID_FRAME
The bit in the SDO COB-ID specifying whether to use an 11-bit (0) or 29-bit (1) CAN-ID.
Definition: sdo.h:39
void co_sdo_req_clear(struct co_sdo_req *req)
Clears a CANopen SDO upload/download request, including its buffer.
Definition: sdo.c:129
#define CO_SDO_AC_NO_DATA
SDO abort code: No data available.
Definition: sdo.h:175
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_BLK_SIZE
SDO abort code: Invalid block size (block mode only).
Definition: sdo.h:72
#define CO_SDO_COBID_VALID
The bit in the SDO COB-ID specifying whether the SDO exists and is valid.
Definition: sdo.h:33
int co_sdo_req_last(const struct co_sdo_req *req)
Returns 1 if the specified request includes the last segment, and 0 otherwise.
Definition: sdo.h:346
#define CO_SDO_AC_PARAM_VAL
SDO abort code: Invalid value for parameter (download only).
Definition: sdo.h:135
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_BLK_CRC
SDO abort code: CRC error (block mode only).
Definition: sdo.h:78
#define CO_SDO_AC_NO_MEM
SDO abort code: Out of memory.
Definition: sdo.h:81
#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 MAX(a, b)
Returns the maximum of a and b.
Definition: util.h:65
void * membuf_begin(const struct membuf *buf)
Returns a pointer to the first byte in a memory buffer.
Definition: membuf.h:144
size_t membuf_reserve(struct membuf *buf, size_t size)
Resizes a memory buffer, if necessary, to make room for at least an additional size bytes.
Definition: membuf.c:46
void membuf_fini(struct membuf *buf)
Finalizes a memory buffer.
Definition: membuf.c:38
void membuf_flush(struct membuf *buf, size_t size)
Flushes size bytes from the beginning of a memory buffer.
Definition: membuf.c:75
size_t membuf_write(struct membuf *buf, const void *ptr, size_t size)
Writes data to a memory buffer.
Definition: membuf.h:192
void membuf_clear(struct membuf *buf)
Clears a memory buffer.
Definition: membuf.h:150
void membuf_init(struct membuf *buf)
Initializes a memory buffer.
Definition: membuf.h:138
size_t membuf_size(const struct membuf *buf)
Returns the total number of bytes written to a memory buffer.
Definition: membuf.h:156
#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
#define CAN_FLAG_EDL
The Extended Data Length (EDL) flag.
Definition: msg.h:55
void can_timer_stop(can_timer_t *timer)
Stops a CAN timer and unregisters it with a network interface.
Definition: net.c:468
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_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_stop(can_recv_t *recv)
Stops a CAN frame receiver from processing frames and unregisters it with the network interface.
Definition: net.c:613
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
This is the internal header file of the CANopen library.
This is the internal header file of the Service Data Object (SDO) declarations.
#define CO_SDO_SEQ_LAST
The mask to get/set the last segment bit from an SDO command byte.
Definition: sdo.h:151
#define CO_SDO_SEG_TOGGLE
The mask to get/set the toggle bit from an SDO command byte.
Definition: sdo.h:117
#define CO_SDO_CCS_DN_INI_REQ
The SDO client command specifier 'download initiate' request.
Definition: sdo.h:55
#define CO_SDO_BLK_SIZE_IND
The SDO size indicator flag indicating that the data set size is indicated.
Definition: sdo.h:145
#define CO_SDO_CS_MASK
The mask to extract the command specifier (CS) from an SDO command byte.
Definition: sdo.h:31
#define CO_SDO_BLK_SIZE_SET(n)
Sets the SDO size indicator, indicating n bytes contain segment data (in the range [0....
Definition: sdo.h:173
#define CO_SDO_INI_SIZE_EXP_GET(cs)
Retrieves the number of bytes containing expedited data from the SDO size indicator.
Definition: sdo.h:105
#define CO_SDO_SCS_UP_SEG_RES
The SDO server command specifier 'upload segment' response.
Definition: sdo.h:46
#define CO_SDO_SEG_SIZE_SET(n)
Sets the SDO size indicator, indicating n bytes contain segment data (in the range [0....
Definition: sdo.h:139
#define CO_SDO_SC_END_BLK
The SDO server/client subcommand 'end block download/upload'.
Definition: sdo.h:79
#define CO_SDO_SCS_UP_INI_RES
The SDO server command specifier 'upload initiate' response.
Definition: sdo.h:43
#define CO_SDO_SCS_DN_SEG_RES
The SDO server command specifier 'download segment' response.
Definition: sdo.h:40
#define CO_SDO_CS_ABORT
The SDO client/server command specifier 'abort transfer' request.
Definition: sdo.h:34
#define CO_SDO_CCS_BLK_DN_REQ
The SDO client command specifier 'block download' request.
Definition: sdo.h:67
#define CO_SDO_CCS_UP_INI_REQ
The SDO client command specifier 'upload initiate' request.
Definition: sdo.h:61
#define CO_SDO_SC_MASK
The mask to extract the subcommand (SC) from an SDO command byte.
Definition: sdo.h:73
#define CO_SDO_BLK_CRC
The SDO CRC support flag.
Definition: sdo.h:148
#define CO_SDO_CCS_DN_SEG_REQ
The SDO client command specifier 'download segment' request.
Definition: sdo.h:58
#define CO_SDO_INI_SIZE_IND
The SDO size indicator flag indicating that the data set size is indicated.
Definition: sdo.h:94
#define CO_SDO_SCS_BLK_DN_RES
The SDO server command specifier 'block download' response.
Definition: sdo.h:49
#define CO_SDO_INI_SIZE_EXP_SET(n)
Sets the SDO size indicator, indicating the expedited transfer of n bytes (in the range [1....
Definition: sdo.h:113
#define CO_SDO_SCS_BLK_UP_RES
The SDO server command specifier 'block upload' response.
Definition: sdo.h:52
#define CO_SDO_MAX_SEQNO
The maximum sequence number (or segments per block).
Definition: sdo.h:176
#define CO_SDO_SEG_SIZE_GET(cs)
Retrieves the number of bytes containing segment data from the SDO size indicator.
Definition: sdo.h:131
#define CO_SDO_SEG_LAST
The mask to get/set the last segment bit from an SDO command byte.
Definition: sdo.h:142
#define CO_SDO_BLK_SIZE_GET(cs)
Retrieves the number of bytes containing segment data from the SDO size indicator.
Definition: sdo.h:165
#define CO_SDO_SC_START_UP
The SDO client subcommand 'start upload'.
Definition: sdo.h:85
#define CO_SDO_SC_BLK_RES
The SDO client/client subcommand 'block download/upload' response.
Definition: sdo.h:82
#define CO_SDO_CCS_BLK_UP_REQ
The SDO client command specifier 'block upload' request.
Definition: sdo.h:70
#define CO_SDO_INI_SIZE_EXP
The SDO size indicator flag indicating expedited transfer.
Definition: sdo.h:97
#define CO_SDO_SCS_DN_INI_RES
The SDO server command specifier 'download initiate' response.
Definition: sdo.h:37
#define CO_SDO_CCS_UP_SEG_REQ
The SDO client command specifier 'upload segment' request.
Definition: sdo.h:64
#define CO_SDO_SC_INI_BLK
The SDO server/client subcommand 'initiate download/upload'.
Definition: sdo.h:76
static co_ssdo_state_t * co_ssdo_wait_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'waiting' state.
Definition: ssdo.c:920
static co_ssdo_state_t * co_ssdo_wait_on_recv(co_ssdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'waiting' state.
Definition: ssdo.c:929
static void co_ssdo_send_blk_up_ini_res(co_ssdo_t *sdo)
Sends a Server-SDO 'block upload initiate' response.
Definition: ssdo.c:1747
static co_ssdo_state_t * co_ssdo_up_seg_on_time(co_ssdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'upload segment' state.
Definition: ssdo.c:1107
void co_ssdo_destroy(co_ssdo_t *ssdo)
Destroys a CANopen Server-SDO service.
Definition: ssdo.c:657
static void co_ssdo_send_dn_seg_res(co_ssdo_t *sdo)
Sends a Server-SDO 'download segment' response.
Definition: ssdo.c:1641
static co_ssdo_state_t * co_ssdo_up_seg_on_recv(co_ssdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'upload segment' state.
Definition: ssdo.c:1115
static void co_ssdo_init_seg_res(co_ssdo_t *sdo, struct can_msg *msg, uint8_t cs)
Initializes a Server-SDO download/upload segment response CAN frame.
Definition: ssdo.c:1819
static co_ssdo_state_t * co_ssdo_blk_dn_end_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'block download end' state.
Definition: ssdo.c:1266
co_unsigned8_t co_ssdo_get_num(const co_ssdo_t *sdo)
Returns the SDO number of a Server-SDO.
Definition: ssdo.c:683
static co_ssdo_state_t *const co_ssdo_blk_dn_end_state
The 'block download end' state.
Definition: ssdo.c:317
static void co_ssdo_send_blk_up_sub_res(co_ssdo_t *sdo, int last)
Sends a Server-SDO 'block upload sub-block' response.
Definition: ssdo.c:1761
static co_ssdo_state_t * co_ssdo_blk_dn_sub_on_time(co_ssdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'block download sub-block' state.
Definition: ssdo.c:1206
static co_ssdo_state_t * co_ssdo_blk_dn_end_on_recv(co_ssdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'block download end' state.
Definition: ssdo.c:1280
static co_unsigned32_t co_ssdo_up_ind(co_ssdo_t *sdo)
Processes an upload indication of a Server-SDO by checking access to the requested sub-object and wri...
Definition: ssdo.c:1563
static co_ssdo_state_t * co_ssdo_dn_seg_on_time(co_ssdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'download segment' state.
Definition: ssdo.c:1007
static void co_ssdo_send_blk_up_end_res(co_ssdo_t *sdo)
Sends a Server-SDO 'block upload end' response.
Definition: ssdo.c:1782
static co_ssdo_state_t * co_ssdo_blk_up_end_on_recv(co_ssdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'block upload end' state.
Definition: ssdo.c:1489
static co_ssdo_state_t * co_ssdo_blk_up_sub_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
The 'block upload initiate' state.
Definition: ssdo.c:1391
static void co_ssdo_send_up_seg_res(co_ssdo_t *sdo, int last)
Sends a Server-SDO 'upload segment' response.
Definition: ssdo.c:1686
static co_unsigned32_t co_ssdo_dn_ind(co_ssdo_t *sdo)
Processes a download indication of a Server-SDO by checking access to the requested sub-object and re...
Definition: ssdo.c:1545
static void co_ssdo_send_blk_dn_sub_res(co_ssdo_t *sdo)
Sends a Server-SDO 'block upload sub-block' response.
Definition: ssdo.c:1721
static co_ssdo_state_t * co_ssdo_blk_dn_sub_on_recv(co_ssdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'block download sub-block' state.
Definition: ssdo.c:1214
void co_ssdo_set_timeout(co_ssdo_t *sdo, int timeout)
Sets the timeout of a Server-SDO.
Definition: ssdo.c:707
static int co_ssdo_update(co_ssdo_t *sdo)
Updates and (de)activates a Server-SDO service.
Definition: ssdo.c:718
const struct co_sdo_par * co_ssdo_get_par(const co_ssdo_t *sdo)
Returns a pointer to the SDO parameter record of a Server-SDO.
Definition: ssdo.c:691
static void co_ssdo_emit_time(co_ssdo_t *sdo, const struct timespec *tp)
Invokes the 'timeout' transition function of the current state of a Server-SDO service.
Definition: ssdo.c:900
static co_ssdo_state_t *const co_ssdo_blk_up_sub_state
The 'block upload sub-block' state.
Definition: ssdo.c:353
static co_unsigned32_t co_1200_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen objects 1200..127F (SDO server para...
Definition: ssdo.c:745
static co_ssdo_state_t * co_ssdo_blk_dn_ini_on_recv(co_ssdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'block download initiate' state.
Definition: ssdo.c:1154
static co_ssdo_state_t *const co_ssdo_blk_up_end_state
The 'block upload end' state.
Definition: ssdo.c:376
static int co_ssdo_recv(const struct can_msg *msg, void *data)
The CAN receive callback function for a Server-SDO service.
Definition: ssdo.c:847
static int co_ssdo_timer(const struct timespec *tp, void *data)
The CAN timer callback function for a Server-SDO service.
Definition: ssdo.c:869
static co_ssdo_state_t *const co_ssdo_dn_seg_state
The 'download segment' state.
Definition: ssdo.c:227
static co_ssdo_state_t * co_ssdo_up_ini_on_recv(co_ssdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'upload initiate' state.
Definition: ssdo.c:1064
static co_ssdo_state_t * co_ssdo_up_seg_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
The 'upload initiate' state.
Definition: ssdo.c:1101
static void co_ssdo_emit_recv(co_ssdo_t *sdo, const struct can_msg *msg)
Invokes the 'CAN frame received' transition function of the current state of a Server-SDO service.
Definition: ssdo.c:910
static co_unsigned32_t co_ssdo_up_buf(co_ssdo_t *sdo, size_t nbyte)
Copies at most nbyte bytes from a CANopen SDO upload request, obtaining more bytes with co_ssdo_up_in...
Definition: ssdo.c:1589
static void co_ssdo_send_dn_ini_res(co_ssdo_t *sdo)
Sends a Server-SDO 'download initiate' response.
Definition: ssdo.c:1629
co_ssdo_t * co_ssdo_create(can_net_t *net, co_dev_t *dev, co_unsigned8_t num)
Creates a new CANopen Server-SDO service.
Definition: ssdo.c:630
static co_ssdo_state_t * co_ssdo_abort_res(co_ssdo_t *sdo, co_unsigned32_t ac)
Sends an abort transfer request and aborts any ongoing transfer by invoking co_ssdo_abort_ind().
Definition: ssdo.c:1537
static co_ssdo_state_t * co_ssdo_dn_ini_on_recv(co_ssdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'download initiate' state.
Definition: ssdo.c:949
static void co_ssdo_init_ini_res(co_ssdo_t *sdo, struct can_msg *msg, uint8_t cs)
Initializes a Server-SDO download/upload initiate response CAN frame.
Definition: ssdo.c:1799
can_net_t * co_ssdo_get_net(const co_ssdo_t *sdo)
Returns a pointer to the CAN network of a Server-SDO.
Definition: ssdo.c:667
static void co_ssdo_send_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
Sends an abort transfer request.
Definition: ssdo.c:1618
static void co_ssdo_send_blk_dn_end_res(co_ssdo_t *sdo)
Sends a Server-SDO 'block download end' response.
Definition: ssdo.c:1735
static co_ssdo_state_t * co_ssdo_blk_dn_end_on_time(co_ssdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'block download end' state.
Definition: ssdo.c:1272
static co_ssdo_state_t * co_ssdo_dn_seg_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
The 'download initiate' state.
Definition: ssdo.c:1001
static co_ssdo_state_t *const co_ssdo_blk_dn_sub_state
The 'block download sub-block' state.
Definition: ssdo.c:293
static co_ssdo_state_t * co_ssdo_dn_seg_on_recv(co_ssdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'download segment' state.
Definition: ssdo.c:1015
static void co_ssdo_send_blk_dn_ini_res(co_ssdo_t *sdo)
Sends a Server-SDO 'block download initiate' response.
Definition: ssdo.c:1708
static co_ssdo_state_t *const co_ssdo_up_seg_state
The 'upload segment' state.
Definition: ssdo.c:257
static co_ssdo_state_t * co_ssdo_blk_up_sub_on_time(co_ssdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'block upload sub-block' state.
Definition: ssdo.c:1397
static co_ssdo_state_t * co_ssdo_blk_up_sub_on_recv(co_ssdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'block upload sub-block' state.
Definition: ssdo.c:1405
int co_ssdo_get_timeout(const co_ssdo_t *sdo)
Returns the timeout (in milliseconds) of a Server-SDO.
Definition: ssdo.c:699
static co_ssdo_state_t * co_ssdo_blk_up_end_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'block upload end' state.
Definition: ssdo.c:1475
static co_ssdo_state_t * co_ssdo_blk_up_ini_on_recv(co_ssdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'block upload initiate' state.
Definition: ssdo.c:1321
co_dev_t * co_ssdo_get_dev(const co_ssdo_t *sdo)
Returns a pointer to the CANopen device of a Server-SDO.
Definition: ssdo.c:675
static co_ssdo_state_t * co_ssdo_abort_ind(co_ssdo_t *sdo)
Processes an abort transfer indication by aborting any ongoing transfer of a Server-SDO and returning...
Definition: ssdo.c:1513
static void co_ssdo_enter(co_ssdo_t *sdo, co_ssdo_state_t *next)
Enters the specified state of a Server-SDO service.
Definition: ssdo.c:881
static co_ssdo_state_t * co_ssdo_blk_dn_sub_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
The 'block download initiate' state.
Definition: ssdo.c:1200
static co_ssdo_state_t * co_ssdo_blk_up_end_on_time(co_ssdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'block upload end' state.
Definition: ssdo.c:1481
static void co_ssdo_send_up_exp_res(co_ssdo_t *sdo)
Sends a Server-SDO 'upload initiate' (expedited) response.
Definition: ssdo.c:1654
static co_ssdo_state_t *const co_ssdo_wait_state
The 'waiting' state.
Definition: ssdo.c:192
static void co_ssdo_emit_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
Invokes the 'abort' transition function of the current state of a Server-SDO service.
Definition: ssdo.c:890
static void co_ssdo_send_up_ini_res(co_ssdo_t *sdo)
Sends a Server-SDO 'upload initiate' response.
Definition: ssdo.c:1672
This header file is part of the CANopen library; it contains the Server-SDO declarations.
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 Server-SDO state.
Definition: ssdo.c:144
co_ssdo_state_t *(* on_time)(co_ssdo_t *sdo, const struct timespec *tp)
A pointer to the transition function invoked when a timeout occurs.
Definition: ssdo.c:163
co_ssdo_state_t *(* on_recv)(co_ssdo_t *sdo, const struct can_msg *msg)
A pointer to the transition function invoked when a CAN frame has been received.
Definition: ssdo.c:173
co_ssdo_state_t *(* on_abort)(co_ssdo_t *sdo, co_unsigned32_t ac)
A pointer to the transition function invoked when an abort code has been received.
Definition: ssdo.c:154
A CANopen Server-SDO.
Definition: ssdo.c:43
struct co_sdo_par par
The SDO parameter record.
Definition: ssdo.c:51
co_unsigned16_t idx
The current object index.
Definition: ssdo.c:61
co_ssdo_state_t * state
A pointer to the current state.
Definition: ssdo.c:59
can_net_t * net
A pointer to a CAN network interface.
Definition: ssdo.c:45
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: ssdo.c:53
uint8_t ackseq
The sequence number of the last successfully received segment.
Definition: ssdo.c:69
int timeout
The SDO timeout (in milliseconds).
Definition: ssdo.c:55
co_dev_t * dev
A pointer to a CANopen device.
Definition: ssdo.c:47
unsigned gencrc
A flag indicating whether a CRC should be generated.
Definition: ssdo.c:71
uint16_t crc
The generated CRC.
Definition: ssdo.c:73
struct membuf buf
The buffer.
Definition: ssdo.c:77
uint8_t toggle
The current value of the toggle bit.
Definition: ssdo.c:65
can_timer_t * timer
A pointer to the CAN timer.
Definition: ssdo.c:57
co_unsigned8_t subidx
The current object sub-index.
Definition: ssdo.c:63
struct co_sdo_req req
The SDO request.
Definition: ssdo.c:75
uint8_t blksize
The number of segments per block.
Definition: ssdo.c:67
co_unsigned8_t num
The SDO number.
Definition: ssdo.c:49
size_t nbyte
The number of bytes in req already copied to buf.
Definition: ssdo.c:79
A CANopen sub-object.
Definition: obj.h:54
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
An SDO parameter record.
Definition: sdo.h:45
co_unsigned32_t cobid_res
COB-ID server -> client.
Definition: sdo.h:51
co_unsigned8_t n
Highest sub-index supported.
Definition: sdo.h:47
co_unsigned32_t cobid_req
COB-ID client -> server.
Definition: sdo.h:49
co_unsigned8_t id
Node-ID of SDO's client resp. server.
Definition: sdo.h:53
A CANopen SDO upload/download request.
Definition: sdo.h:178
size_t offset
The offset of the bytes at buf.
Definition: sdo.h:193
size_t size
The total size (in bytes) of the value to be uploaded/downloaded.
Definition: sdo.h:184
const void * buf
A pointer to the next bytes to be uploaded/downloaded.
Definition: sdo.h:186
size_t nbyte
The number of bytes available at buf.
Definition: sdo.h:188
A memory buffer.
Definition: membuf.h:35
A time type with nanosecond resolution.
Definition: time.h:83
#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 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