Lely core libraries 2.3.5
ssdo.c
Go to the documentation of this file.
1
23
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#if !LELY_NO_STDIO
36#include <inttypes.h>
37#endif
38#include <stdlib.h>
39#include <string.h>
40
41#if LELY_NO_MALLOC
42#ifndef CO_SSDO_MEMBUF_SIZE
48#if LELY_NO_CO_SSDO_BLK
49#define CO_SSDO_MEMBUF_SIZE 7
50#else // !LELY_NO_CO_SSDO_BLK
51#define CO_SSDO_MEMBUF_SIZE (CO_SDO_MAX_SEQNO * 7)
52#endif // !LELY_NO_CO_SSDO_BLK
53#endif // !CO_SSDO_MEMBUF_SIZE
54#endif // LELY_NO_MALLOC
55
56#if !LELY_NO_CO_SSDO_BLK
57#ifndef CO_SSDO_MAX_SEQNO
58#if LELY_NO_MALLOC
59#define CO_SSDO_MAX_SEQNO MIN(CO_SDO_MAX_SEQNO, (CO_SSDO_MEMBUF_SIZE / 7))
60#else // !LELY_NO_MALLOC
61#define CO_SSDO_MAX_SEQNO CO_SDO_MAX_SEQNO
62#endif // !LELY_NO_MALLOC
63#endif // !CO_SSDO_MAX_SEQNO
64#endif // !LELY_NO_CO_SSDO_BLK
65
66struct __co_ssdo_state;
68typedef const struct __co_ssdo_state co_ssdo_state_t;
69
71struct __co_ssdo {
77 co_unsigned8_t num;
89 co_unsigned16_t idx;
91 co_unsigned8_t subidx;
93 co_unsigned8_t toggle;
94#if !LELY_NO_CO_SSDO_BLK
96 co_unsigned8_t blksize;
98 co_unsigned8_t ackseq;
100 unsigned gencrc : 1;
102 co_unsigned16_t crc;
103#endif
107 struct membuf buf;
109 size_t nbyte;
110#if LELY_NO_MALLOC
115 char begin[CO_SSDO_MEMBUF_SIZE];
116#endif
117};
118
125static int co_ssdo_update(co_ssdo_t *sdo);
126
133static co_unsigned32_t co_1200_dn_ind(
134 co_sub_t *sub, struct co_sdo_req *req, void *data);
135
141static int co_ssdo_recv(const struct can_msg *msg, void *data);
142
148static int co_ssdo_timer(const struct timespec *tp, void *data);
149
151static inline void co_ssdo_enter(co_ssdo_t *sdo, co_ssdo_state_t *next);
152
160static inline void co_ssdo_emit_abort(co_ssdo_t *sdo, co_unsigned32_t ac);
161
169static inline void co_ssdo_emit_time(co_ssdo_t *sdo, const struct timespec *tp);
170
178static inline void co_ssdo_emit_recv(co_ssdo_t *sdo, const struct can_msg *msg);
179
191 co_ssdo_state_t *(*on_abort)(co_ssdo_t *sdo, co_unsigned32_t ac);
200 co_ssdo_state_t *(*on_time)(co_ssdo_t *sdo, const struct timespec *tp);
210 co_ssdo_state_t *(*on_recv)(co_ssdo_t *sdo, const struct can_msg *msg);
211};
212
213#define LELY_CO_DEFINE_STATE(name, ...) \
214 static co_ssdo_state_t *const name = &(co_ssdo_state_t){ __VA_ARGS__ };
215
217LELY_CO_DEFINE_STATE(co_ssdo_stopped_state, .on_recv = NULL)
218
219
221 co_ssdo_t *sdo, co_unsigned32_t ac);
222
225 co_ssdo_t *sdo, const struct can_msg *msg);
226
228// clang-format off
229LELY_CO_DEFINE_STATE(co_ssdo_wait_state,
230 .on_abort = &co_ssdo_wait_on_abort,
231 .on_recv = &co_ssdo_wait_on_recv
233// clang-format on
234
235
240 co_ssdo_t *sdo, const struct can_msg *msg);
241
243// LELY_CO_DEFINE_STATE(co_ssdo_dn_ini_state,
244// .on_recv = &co_ssdo_dn_ini_on_recv
245//)
246
249 co_ssdo_t *sdo, co_unsigned32_t ac);
250
253 co_ssdo_t *sdo, const struct timespec *tp);
254
259 co_ssdo_t *sdo, const struct can_msg *msg);
260
262// clang-format off
263LELY_CO_DEFINE_STATE(co_ssdo_dn_seg_state,
264 .on_abort = &co_ssdo_dn_seg_on_abort,
265 .on_time = &co_ssdo_dn_seg_on_time,
266 .on_recv = &co_ssdo_dn_seg_on_recv
268// clang-format on
269
272 co_ssdo_t *sdo, const struct can_msg *msg);
273
275// LELY_CO_DEFINE_STATE(co_ssdo_up_ini_state,
276// .on_recv = &co_ssdo_up_ini_on_recv
277//)
278
281 co_ssdo_t *sdo, co_unsigned32_t ac);
282
285 co_ssdo_t *sdo, const struct timespec *tp);
286
289 co_ssdo_t *sdo, const struct can_msg *msg);
290
292// clang-format off
293LELY_CO_DEFINE_STATE(co_ssdo_up_seg_state,
294 .on_abort = &co_ssdo_up_seg_on_abort,
295 .on_time = &co_ssdo_up_seg_on_time,
296 .on_recv = &co_ssdo_up_seg_on_recv
298// clang-format on
299
300#if !LELY_NO_CO_SSDO_BLK
301
307 co_ssdo_t *sdo, const struct can_msg *msg);
308
310// LELY_CO_DEFINE_STATE(co_ssdo_blk_dn_ini_state,
311// .on_recv = &co_ssdo_blk_dn_ini_on_recv
312//)
313
316 co_ssdo_t *sdo, co_unsigned32_t ac);
317
320 co_ssdo_t *sdo, const struct timespec *tp);
321
327 co_ssdo_t *sdo, const struct can_msg *msg);
328
330// clang-format off
331LELY_CO_DEFINE_STATE(co_ssdo_blk_dn_sub_state,
332 .on_abort = &co_ssdo_blk_dn_sub_on_abort,
333 .on_time = &co_ssdo_blk_dn_sub_on_time,
336// clang-format on
337
338
340 co_ssdo_t *sdo, co_unsigned32_t ac);
341
344 co_ssdo_t *sdo, const struct timespec *tp);
345
351 co_ssdo_t *sdo, const struct can_msg *msg);
352
354// clang-format off
355LELY_CO_DEFINE_STATE(co_ssdo_blk_dn_end_state,
356 .on_abort = &co_ssdo_blk_dn_end_on_abort,
357 .on_time = &co_ssdo_blk_dn_end_on_time,
360// clang-format on
361
367 co_ssdo_t *sdo, const struct can_msg *msg);
368
370// LELY_CO_DEFINE_STATE(co_ssdo_blk_up_ini_state,
371// .on_recv = &co_ssdo_blk_up_ini_on_recv
372//)
373
376 co_ssdo_t *sdo, co_unsigned32_t ac);
377
380 co_ssdo_t *sdo, const struct timespec *tp);
381
387 co_ssdo_t *sdo, const struct can_msg *msg);
388
390// clang-format off
391LELY_CO_DEFINE_STATE(co_ssdo_blk_up_sub_state,
392 .on_abort = &co_ssdo_blk_up_sub_on_abort,
393 .on_time = &co_ssdo_blk_up_sub_on_time,
396// clang-format on
397
400 co_ssdo_t *sdo, co_unsigned32_t ac);
401
404 co_ssdo_t *sdo, const struct timespec *tp);
405
410 co_ssdo_t *sdo, const struct can_msg *msg);
411
413// clang-format off
414LELY_CO_DEFINE_STATE(co_ssdo_blk_up_end_state,
415 .on_abort = &co_ssdo_blk_up_end_on_abort,
416 .on_time = &co_ssdo_blk_up_end_on_time,
419// clang-format on
420
421#endif // !LELY_NO_CO_SSDO_BLK
422
423#undef LELY_CO_DEFINE_STATE
424
432
444static co_ssdo_state_t *co_ssdo_abort_res(co_ssdo_t *sdo, co_unsigned32_t ac);
445
452static co_unsigned32_t co_ssdo_dn_ind(co_ssdo_t *sdo);
453
460static co_unsigned32_t co_ssdo_up_ind(co_ssdo_t *sdo);
461
468static co_unsigned32_t co_ssdo_up_buf(co_ssdo_t *sdo, size_t nbyte);
469
476static void co_ssdo_send_abort(co_ssdo_t *sdo, co_unsigned32_t ac);
477
479static void co_ssdo_send_dn_ini_res(co_ssdo_t *sdo);
480
482static void co_ssdo_send_dn_seg_res(co_ssdo_t *sdo);
483
485static void co_ssdo_send_up_exp_res(co_ssdo_t *sdo);
486
488static void co_ssdo_send_up_ini_res(co_ssdo_t *sdo);
489
496static void co_ssdo_send_up_seg_res(co_ssdo_t *sdo, int last);
497
498#if !LELY_NO_CO_SSDO_BLK
499
501static void co_ssdo_send_blk_dn_ini_res(co_ssdo_t *sdo);
502
504static void co_ssdo_send_blk_dn_sub_res(co_ssdo_t *sdo);
505
507static void co_ssdo_send_blk_dn_end_res(co_ssdo_t *sdo);
508
510static void co_ssdo_send_blk_up_ini_res(co_ssdo_t *sdo);
511
518static void co_ssdo_send_blk_up_sub_res(co_ssdo_t *sdo, int last);
519
521static void co_ssdo_send_blk_up_end_res(co_ssdo_t *sdo);
522
523#endif // !LELY_NO_CO_SSDO_BLK
524
532static void co_ssdo_init_ini_res(
533 co_ssdo_t *sdo, struct can_msg *msg, co_unsigned8_t cs);
534
542static void co_ssdo_init_seg_res(
543 co_ssdo_t *sdo, struct can_msg *msg, co_unsigned8_t cs);
544
545void *
546__co_ssdo_alloc(void)
547{
548 void *ptr = malloc(sizeof(struct __co_ssdo));
549#if !LELY_NO_ERRNO
550 if (!ptr)
551 set_errc(errno2c(errno));
552#endif
553 return ptr;
554}
555
556void
557__co_ssdo_free(void *ptr)
558{
559 free(ptr);
560}
561
562struct __co_ssdo *
563__co_ssdo_init(struct __co_ssdo *sdo, can_net_t *net, co_dev_t *dev,
564 co_unsigned8_t num)
565{
566 assert(sdo);
567 assert(net);
568 assert(dev);
569
570 int errc = 0;
571
572 if (!num || num > CO_NUM_SDOS) {
573 errc = errnum2c(ERRNUM_INVAL);
574 goto error_param;
575 }
576
577 // Find the SDO server parameter in the object dictionary. The default
578 // SDO (1200) is optional.
579 co_obj_t *obj_1200 = co_dev_find_obj(dev, 0x1200 + num - 1);
580 if (num != 1 && !obj_1200) {
581 errc = errnum2c(ERRNUM_INVAL);
582 goto error_param;
583 }
584
585 sdo->net = net;
586 sdo->dev = dev;
587 sdo->num = num;
588
589 // Initialize the SDO parameter record with the default values.
590 sdo->par.n = 3;
591 sdo->par.id = co_dev_get_id(dev);
592 sdo->par.cobid_req = 0x600 + sdo->par.id;
593 sdo->par.cobid_res = 0x580 + sdo->par.id;
594
595 sdo->recv = can_recv_create();
596 if (!sdo->recv) {
597 errc = get_errc();
598 goto error_create_recv;
599 }
601
602 sdo->timeout = 0;
603
604 sdo->timer = can_timer_create();
605 if (!sdo->timer) {
606 errc = get_errc();
607 goto error_create_timer;
608 }
610
612
613 sdo->idx = 0;
614 sdo->subidx = 0;
615
616 sdo->toggle = 0;
617#if !LELY_NO_CO_SSDO_BLK
618 sdo->blksize = 0;
619 sdo->ackseq = 0;
620 sdo->gencrc = 0;
621 sdo->crc = 0;
622#endif
623
624 co_sdo_req_init(&sdo->req);
625#if LELY_NO_MALLOC
626 membuf_init(&sdo->buf, sdo->begin, CO_SSDO_MEMBUF_SIZE);
627#else
628 membuf_init(&sdo->buf, NULL, 0);
629#endif
630 sdo->nbyte = 0;
631#if LELY_NO_MALLOC
632 memset(sdo->begin, 0, CO_SSDO_MEMBUF_SIZE);
633#endif
634
635 if (co_ssdo_start(sdo) == -1) {
636 errc = get_errc();
637 goto error_start;
638 }
639
640 return sdo;
641
642 // co_ssdo_stop(sdo);
643error_start:
645error_create_timer:
647error_create_recv:
648error_param:
649 set_errc(errc);
650 return NULL;
651}
652
653void
654__co_ssdo_fini(struct __co_ssdo *sdo)
655{
656 assert(sdo);
657 assert(sdo->num >= 1 && sdo->num <= CO_NUM_SDOS);
658
659 co_ssdo_stop(sdo);
660
661 membuf_fini(&sdo->buf);
662 co_sdo_req_fini(&sdo->req);
663
665
667}
668
669co_ssdo_t *
671{
672 trace("creating Server-SDO %d", num);
673
674 int errc = 0;
675
676 co_ssdo_t *sdo = __co_ssdo_alloc();
677 if (!sdo) {
678 errc = get_errc();
679 goto error_alloc_sdo;
680 }
681
682 if (!__co_ssdo_init(sdo, net, dev, num)) {
683 errc = get_errc();
684 goto error_init_sdo;
685 }
686
687 return sdo;
688
689error_init_sdo:
690 __co_ssdo_free(sdo);
691error_alloc_sdo:
692 set_errc(errc);
693 return NULL;
694}
695
696void
698{
699 if (ssdo) {
700 trace("destroying Server-SDO %d", ssdo->num);
701 __co_ssdo_fini(ssdo);
702 __co_ssdo_free(ssdo);
703 }
704}
705
706int
708{
709 assert(sdo);
710
711 if (!co_ssdo_is_stopped(sdo))
712 return 0;
713
715
716 co_unsigned16_t idx_1200 = 0x1200 + sdo->num - 1;
717 co_obj_t *obj_1200 = co_dev_find_obj(sdo->dev, idx_1200);
718 if (obj_1200) {
719 // Copy the SDO parameters.
720 memset(&sdo->par, 0, sizeof(sdo->par));
721 sdo->par.n = co_dev_get_val_u8(sdo->dev, idx_1200, 0);
722 sdo->par.cobid_req = co_dev_get_val_u32(sdo->dev, idx_1200, 1);
723 sdo->par.cobid_res = co_dev_get_val_u32(sdo->dev, idx_1200, 2);
724 sdo->par.id = co_dev_get_val_u8(sdo->dev, idx_1200, 3);
725 // Set the download indication function for the SDO parameter
726 // record.
727 co_obj_set_dn_ind(obj_1200, &co_1200_dn_ind, sdo);
728 }
729
730 if (co_ssdo_update(sdo) == -1)
731 goto error_update;
732
733 return 0;
734
735error_update:
736 co_ssdo_stop(sdo);
737 return -1;
738}
739
740void
742{
743 assert(sdo);
744
745 if (co_ssdo_is_stopped(sdo))
746 return;
747
748 // Abort any ongoing transfer.
750
751 can_timer_stop(sdo->timer);
752 can_recv_stop(sdo->recv);
753
754 // Remove the download indication functions for the SDO parameter
755 // record.
756 co_obj_t *obj_1200 = co_dev_find_obj(sdo->dev, 0x1200 + sdo->num - 1);
757 if (obj_1200)
758 co_obj_set_dn_ind(obj_1200, NULL, NULL);
759
761}
762
763int
765{
766 assert(sdo);
767
768 return sdo->state == co_ssdo_stopped_state;
769}
770
771can_net_t *
773{
774 assert(sdo);
775
776 return sdo->net;
777}
778
779co_dev_t *
781{
782 assert(sdo);
783
784 return sdo->dev;
785}
786
787co_unsigned8_t
789{
790 assert(sdo);
791
792 return sdo->num;
793}
794
795const struct co_sdo_par *
797{
798 assert(sdo);
799
800 return &sdo->par;
801}
802
803int
805{
806 assert(sdo);
807
808 return sdo->timeout;
809}
810
811void
813{
814 assert(sdo);
815
816 if (sdo->timeout && timeout <= 0)
817 can_timer_stop(sdo->timer);
818
819 sdo->timeout = MAX(0, timeout);
820}
821
822static int
824{
825 assert(sdo);
826
827 // Abort any ongoing transfer.
829
830 int valid_req = !(sdo->par.cobid_req & CO_SDO_COBID_VALID);
831 int valid_res = !(sdo->par.cobid_res & CO_SDO_COBID_VALID);
832 if (valid_req && valid_res) {
833 uint_least32_t id = sdo->par.cobid_req;
834 uint_least8_t flags = 0;
835 if (id & CO_SDO_COBID_FRAME) {
836 id &= CAN_MASK_EID;
837 flags |= CAN_FLAG_IDE;
838 } else {
839 id &= CAN_MASK_BID;
840 }
841 can_recv_start(sdo->recv, sdo->net, id, flags);
842 } else {
843 can_recv_stop(sdo->recv);
844 }
845
846 return 0;
847}
848
849static co_unsigned32_t
850co_1200_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
851{
852 assert(sub);
853 assert(req);
854 co_ssdo_t *sdo = data;
855 assert(sdo);
856 assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1200 + sdo->num - 1);
857
858 co_unsigned16_t type = co_sub_get_type(sub);
859 assert(!co_type_is_array(type));
860
861 co_unsigned32_t ac = 0;
862 union co_val val;
863 if (co_sdo_req_dn_val(req, type, &val, &ac) == -1)
864 return ac;
865
866 switch (co_sub_get_subidx(sub)) {
867 case 0: return CO_SDO_AC_NO_WRITE;
868 case 1: {
869 assert(type == CO_DEFTYPE_UNSIGNED32);
870 co_unsigned32_t cobid = val.u32;
871 co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
872 if (cobid == cobid_old)
873 return 0;
874
875 // The CAN-ID cannot be changed when the SDO is and remains
876 // valid.
877 int valid = !(cobid & CO_SDO_COBID_VALID);
878 int valid_old = !(cobid_old & CO_SDO_COBID_VALID);
879 uint_least32_t canid = cobid & CAN_MASK_EID;
880 uint_least32_t canid_old = cobid_old & CAN_MASK_EID;
881 if (valid && valid_old && canid != canid_old)
882 return CO_SDO_AC_PARAM_VAL;
883
884 // A 29-bit CAN-ID is only valid if the frame bit is set.
885 if (!(cobid & CO_SDO_COBID_FRAME)
886 && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))
887 return CO_SDO_AC_PARAM_VAL;
888
889 sdo->par.cobid_req = cobid;
890 break;
891 }
892 case 2: {
893 assert(type == CO_DEFTYPE_UNSIGNED32);
894 co_unsigned32_t cobid = val.u32;
895 co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
896 if (cobid == cobid_old)
897 return 0;
898
899 // The CAN-ID cannot be changed when the SDO is and remains
900 // valid.
901 int valid = !(cobid & CO_SDO_COBID_VALID);
902 int valid_old = !(cobid_old & CO_SDO_COBID_VALID);
903 uint_least32_t canid = cobid & CAN_MASK_EID;
904 uint_least32_t canid_old = cobid_old & CAN_MASK_EID;
905 if (valid && valid_old && canid != canid_old)
906 return CO_SDO_AC_PARAM_VAL;
907
908 // A 29-bit CAN-ID is only valid if the frame bit is set.
909 if (!(cobid & CO_SDO_COBID_FRAME)
910 && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))
911 return CO_SDO_AC_PARAM_VAL;
912
913 sdo->par.cobid_res = cobid;
914 break;
915 }
916 case 3: {
917 assert(type == CO_DEFTYPE_UNSIGNED8);
918 co_unsigned8_t id = val.u8;
919 co_unsigned8_t id_old = co_sub_get_val_u8(sub);
920 if (id == id_old)
921 return 0;
922
923 sdo->par.id = id;
924 break;
925 }
926 default: return CO_SDO_AC_NO_SUB;
927 }
928
929 co_sub_dn(sub, &val);
930
931 co_ssdo_update(sdo);
932 return 0;
933}
934
935static int
936co_ssdo_recv(const struct can_msg *msg, void *data)
937{
938 assert(msg);
939 co_ssdo_t *sdo = data;
940 assert(sdo);
941
942 // Ignore remote frames.
943 if (msg->flags & CAN_FLAG_RTR)
944 return 0;
945
946#if !LELY_NO_CANFD
947 // Ignore CAN FD format frames.
948 if (msg->flags & CAN_FLAG_EDL)
949 return 0;
950#endif
951
952 co_ssdo_emit_recv(sdo, msg);
953
954 return 0;
955}
956
957static int
958co_ssdo_timer(const struct timespec *tp, void *data)
959{
960 assert(tp);
961 co_ssdo_t *sdo = data;
962 assert(sdo);
963
964 co_ssdo_emit_time(sdo, tp);
965
966 return 0;
967}
968
969static inline void
971{
972 assert(sdo);
973
974 if (next)
975 sdo->state = next;
976}
977
978static inline void
979co_ssdo_emit_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
980{
981 assert(sdo);
982 assert(sdo->state);
983 assert(sdo->state->on_recv);
984
985 co_ssdo_enter(sdo, sdo->state->on_abort(sdo, ac));
986}
987
988static inline void
989co_ssdo_emit_time(co_ssdo_t *sdo, const struct timespec *tp)
990{
991 assert(sdo);
992 assert(sdo->state);
993 assert(sdo->state->on_time);
994
995 co_ssdo_enter(sdo, sdo->state->on_time(sdo, tp));
996}
997
998static inline void
999co_ssdo_emit_recv(co_ssdo_t *sdo, const struct can_msg *msg)
1000{
1001 assert(sdo);
1002 assert(sdo->state);
1003 assert(sdo->state->on_recv);
1004
1005 co_ssdo_enter(sdo, sdo->state->on_recv(sdo, msg));
1006}
1007
1008static co_ssdo_state_t *
1009co_ssdo_wait_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
1010{
1011 (void)sdo;
1012 (void)ac;
1013
1014 return NULL;
1015}
1016
1017static co_ssdo_state_t *
1019{
1020 assert(sdo);
1021 assert(msg);
1022
1023 if (msg->len < 1)
1025 co_unsigned8_t cs = msg->data[0];
1026
1027 switch (cs & CO_SDO_CS_MASK) {
1028 case CO_SDO_CCS_DN_INI_REQ: return co_ssdo_dn_ini_on_recv(sdo, msg);
1029 case CO_SDO_CCS_UP_INI_REQ: return co_ssdo_up_ini_on_recv(sdo, msg);
1030#if !LELY_NO_CO_SSDO_BLK
1033#endif
1034 case CO_SDO_CS_ABORT: return NULL;
1035 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1036 }
1037}
1038
1039static co_ssdo_state_t *
1041{
1042 assert(sdo);
1043 assert(msg);
1044
1045 assert(msg->len > 0);
1046 co_unsigned8_t cs = msg->data[0];
1047
1048 // Load the object index and sub-index from the CAN frame.
1049 if (msg->len < 3)
1051 sdo->idx = ldle_u16(msg->data + 1);
1052 if (msg->len < 4)
1054 sdo->subidx = msg->data[3];
1055
1056 trace("SSDO: %04X:%02X: received download request", sdo->idx,
1057 sdo->subidx);
1058
1059 // Obtain the size from the command specifier.
1060 co_sdo_req_clear(&sdo->req);
1061 int exp = !!(cs & CO_SDO_INI_SIZE_EXP);
1062 if (exp) {
1063 if (cs & CO_SDO_INI_SIZE_IND)
1064 sdo->req.size = CO_SDO_INI_SIZE_EXP_GET(cs);
1065 else
1066 sdo->req.size = msg->len - 4;
1067 } else if (cs & CO_SDO_INI_SIZE_IND) {
1068 // 0-pad the data bytes to handle clients which send CAN frames
1069 // less than 8 bytes.
1070 uint_least8_t data[4] = { 0 };
1071 memcpy(data, msg->data + 4, msg->len - 4);
1072 sdo->req.size = ldle_u32(data);
1073 }
1074
1075 if (exp) {
1076 // Perform an expedited transfer.
1077 sdo->req.buf = msg->data + 4;
1078 sdo->req.nbyte = sdo->req.size;
1079 co_unsigned32_t ac = co_ssdo_dn_ind(sdo);
1080 if (ac)
1081 return co_ssdo_abort_res(sdo, ac);
1082 // Finalize the transfer.
1084 return co_ssdo_abort_ind(sdo);
1085 } else {
1087 if (sdo->timeout)
1088 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1089 return co_ssdo_dn_seg_state;
1090 }
1091}
1092
1093static co_ssdo_state_t *
1094co_ssdo_dn_seg_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
1095{
1096 return co_ssdo_abort_res(sdo, ac);
1097}
1098
1099static co_ssdo_state_t *
1101{
1102 (void)tp;
1103
1105}
1106
1107static co_ssdo_state_t *
1109{
1110 assert(sdo);
1111 assert(msg);
1112
1113 if (msg->len < 1)
1115 co_unsigned8_t cs = msg->data[0];
1116
1117 // Check the client command specifier.
1118 switch (cs & CO_SDO_CS_MASK) {
1119 case CO_SDO_CCS_DN_SEG_REQ: break;
1120 case CO_SDO_CS_ABORT: return co_ssdo_abort_ind(sdo);
1121 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1122 }
1123
1124 // Check the value of the toggle bit.
1125 if ((cs & CO_SDO_SEG_TOGGLE) != sdo->toggle)
1126 return co_ssdo_dn_seg_state;
1127
1128 // Obtain the size of the segment.
1129 size_t n = CO_SDO_SEG_SIZE_GET(cs);
1130 if (msg->len < 1 + n)
1132 int last = !!(cs & CO_SDO_SEG_LAST);
1133
1134 if (sdo->req.offset + sdo->req.nbyte + n > sdo->req.size)
1136
1137 sdo->req.buf = msg->data + 1;
1138 sdo->req.offset += sdo->req.nbyte;
1139 sdo->req.nbyte = n;
1140
1141 if (last && !co_sdo_req_last(&sdo->req))
1143
1144 co_unsigned32_t ac = co_ssdo_dn_ind(sdo);
1145 if (ac)
1146 return co_ssdo_abort_res(sdo, ac);
1147
1149
1150 if (last) {
1151 return co_ssdo_abort_ind(sdo);
1152 } else {
1153 if (sdo->timeout)
1154 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1155 return co_ssdo_dn_seg_state;
1156 }
1157}
1158
1159static co_ssdo_state_t *
1161{
1162 assert(sdo);
1163 assert(msg);
1164
1165 // Load the object index and sub-index from the CAN frame.
1166 if (msg->len < 3)
1168 sdo->idx = ldle_u16(msg->data + 1);
1169 if (msg->len < 4)
1171 sdo->subidx = msg->data[3];
1172
1173 trace("SSDO: %04X:%02X: received upload request", sdo->idx,
1174 sdo->subidx);
1175
1176 // Perform access checks and start serializing the value.
1177 co_sdo_req_clear(&sdo->req);
1178 co_unsigned32_t ac = co_ssdo_up_ind(sdo);
1179 if (ac)
1180 return co_ssdo_abort_res(sdo, ac);
1181
1182 if (sdo->req.size && sdo->req.size <= 4) {
1183 // Perform an expedited transfer.
1184 if ((ac = co_ssdo_up_buf(sdo, sdo->req.size)) != 0)
1185 return co_ssdo_abort_res(sdo, ac);
1187 return co_ssdo_abort_ind(sdo);
1188 } else {
1190 if (sdo->timeout)
1191 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1192 return co_ssdo_up_seg_state;
1193 }
1194}
1195
1196static co_ssdo_state_t *
1197co_ssdo_up_seg_on_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
1198{
1199 return co_ssdo_abort_res(sdo, ac);
1200}
1201
1202static co_ssdo_state_t *
1204{
1205 (void)tp;
1206
1208}
1209
1210static co_ssdo_state_t *
1212{
1213 assert(sdo);
1214 assert(msg);
1215
1216 if (msg->len < 1)
1218 co_unsigned8_t cs = msg->data[0];
1219
1220 // Check the client command specifier.
1221 switch (cs & CO_SDO_CS_MASK) {
1222 case CO_SDO_CCS_UP_SEG_REQ: break;
1223 case CO_SDO_CS_ABORT: return co_ssdo_abort_ind(sdo);
1224 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1225 }
1226
1227 // Check the value of the toggle bit.
1228 if ((cs & CO_SDO_SEG_TOGGLE) != sdo->toggle)
1230
1231 membuf_clear(&sdo->buf);
1232 co_unsigned32_t ac = co_ssdo_up_buf(sdo, 7);
1233 if (ac)
1234 return co_ssdo_abort_res(sdo, ac);
1235
1236 int last = co_sdo_req_last(&sdo->req) && sdo->nbyte == sdo->req.nbyte;
1237 co_ssdo_send_up_seg_res(sdo, last);
1238
1239 if (last) {
1240 // Finalize the transfer.
1241 return co_ssdo_abort_ind(sdo);
1242 } else {
1243 if (sdo->timeout)
1244 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1245 return co_ssdo_up_seg_state;
1246 }
1247}
1248
1249#if !LELY_NO_CO_SSDO_BLK
1250
1251static co_ssdo_state_t *
1253{
1254 assert(sdo);
1255 assert(msg);
1256
1257 assert(msg->len > 0);
1258 co_unsigned8_t cs = msg->data[0];
1259
1260 // Check the client subcommand.
1261 if ((cs & 0x01) != CO_SDO_SC_INI_BLK)
1263
1264 // Check if the client supports generating a CRC.
1265 sdo->gencrc = !!(cs & CO_SDO_BLK_CRC);
1266
1267 // Load the object index and sub-index from the CAN frame.
1268 if (msg->len < 3)
1270 sdo->idx = ldle_u16(msg->data + 1);
1271 if (msg->len < 4)
1273 sdo->subidx = msg->data[3];
1274
1275 trace("SSDO: %04X:%02X: received block download request", sdo->idx,
1276 sdo->subidx);
1277
1278 // Obtain the data set size.
1279 co_sdo_req_clear(&sdo->req);
1280 if (cs & CO_SDO_BLK_SIZE_IND) {
1281 // 0-pad the data bytes to handle clients which send CAN frames
1282 // less than 8 bytes.
1283 uint_least8_t data[4] = { 0 };
1284 memcpy(data, msg->data + 4, msg->len - 4);
1285 sdo->req.size = ldle_u32(data);
1286 }
1287
1288 // Use the maximum block size by default.
1289 sdo->blksize = CO_SSDO_MAX_SEQNO;
1290 sdo->ackseq = 0;
1291
1293
1294 if (sdo->timeout)
1295 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1297}
1298
1299static co_ssdo_state_t *
1301{
1302 return co_ssdo_abort_res(sdo, ac);
1303}
1304
1305static co_ssdo_state_t *
1307{
1308 (void)tp;
1309
1311}
1312
1313static co_ssdo_state_t *
1315{
1316 assert(sdo);
1317 assert(msg);
1318
1319 if (msg->len < 1)
1321 co_unsigned8_t cs = msg->data[0];
1322
1323 if (cs == CO_SDO_CS_ABORT)
1324 return co_ssdo_abort_ind(sdo);
1325
1326 co_unsigned8_t seqno = cs & ~CO_SDO_SEQ_LAST;
1327 int last = !!(cs & CO_SDO_SEQ_LAST);
1328
1329 if (!seqno || seqno > sdo->blksize)
1331
1332 // Only accept sequential segments. Dropped segments will be resent
1333 // after the confirmation message.
1334 if (seqno == sdo->ackseq + 1) {
1335 sdo->ackseq++;
1336 // Update the CRC.
1337 if (sdo->gencrc)
1338 sdo->crc = co_crc(
1339 sdo->crc, sdo->req.buf, sdo->req.nbyte);
1340 // Pass the previous frame to the download indication function.
1341 co_unsigned32_t ac = co_ssdo_dn_ind(sdo);
1342 if (ac)
1343 return co_ssdo_abort_res(sdo, ac);
1344 // Determine the number of bytes to copy.
1345 assert(sdo->req.size >= sdo->req.offset + sdo->req.nbyte);
1346 size_t n = MIN(sdo->req.size - sdo->req.offset - sdo->req.nbyte,
1347 7);
1348 if (!last && n < 7)
1350 // Copy the new frame to the SDO request.
1351 membuf_clear(&sdo->buf);
1352 if (!membuf_reserve(&sdo->buf, n))
1354 membuf_write(&sdo->buf, msg->data + 1, n);
1355 sdo->req.buf = membuf_begin(&sdo->buf);
1356 sdo->req.offset += sdo->req.nbyte;
1357 sdo->req.nbyte = membuf_size(&sdo->buf);
1358 }
1359
1360 // If this is the last segment in the block, send a confirmation.
1361 if (seqno == sdo->blksize || last) {
1363 sdo->ackseq = 0;
1364 }
1365
1366 if (sdo->timeout)
1367 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1369}
1370
1371static co_ssdo_state_t *
1373{
1374 return co_ssdo_abort_res(sdo, ac);
1375}
1376
1377static co_ssdo_state_t *
1379{
1380 (void)tp;
1381
1383}
1384
1385static co_ssdo_state_t *
1387{
1388 assert(sdo);
1389 assert(msg);
1390
1391 if (msg->len < 1)
1393 co_unsigned8_t cs = msg->data[0];
1394
1395 // Check the client command specifier.
1396 switch (cs & CO_SDO_CS_MASK) {
1397 case CO_SDO_CCS_BLK_DN_REQ: break;
1398 case CO_SDO_CS_ABORT: return co_ssdo_abort_ind(sdo);
1399 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1400 }
1401
1402 // Check the client subcommand.
1403 if ((cs & CO_SDO_SC_MASK) != CO_SDO_SC_END_BLK)
1405
1406 // Check the total length.
1407 if (sdo->req.size != sdo->req.offset + sdo->req.nbyte)
1409
1410 // Check the number of bytes in the last segment.
1411 co_unsigned8_t n = sdo->req.size ? (sdo->req.size - 1) % 7 + 1 : 0;
1412 if (CO_SDO_BLK_SIZE_GET(cs) != n)
1414
1415 // Check the CRC.
1416 if (sdo->gencrc) {
1417 sdo->crc = co_crc(sdo->crc, sdo->req.buf, sdo->req.nbyte);
1418 co_unsigned16_t crc = ldle_u16(msg->data + 1);
1419 if (sdo->crc != crc)
1421 }
1422
1423 co_unsigned32_t ac = co_ssdo_dn_ind(sdo);
1424 if (ac)
1425 return co_ssdo_abort_res(sdo, ac);
1426
1427 // Finalize the transfer.
1429 return co_ssdo_abort_ind(sdo);
1430}
1431
1432static co_ssdo_state_t *
1434{
1435 assert(sdo);
1436 assert(msg);
1437
1438 assert(msg->len > 0);
1439 co_unsigned8_t cs = msg->data[0];
1440
1441 // Check the client subcommand.
1442 if ((cs & CO_SDO_SC_MASK) != CO_SDO_SC_INI_BLK)
1444
1445 // Check if the client supports generating a CRC.
1446 sdo->gencrc = !!(cs & CO_SDO_BLK_CRC);
1447
1448 // Load the object index and sub-index from the CAN frame.
1449 if (msg->len < 3)
1451 sdo->idx = ldle_u16(msg->data + 1);
1452 if (msg->len < 4)
1454 sdo->subidx = msg->data[3];
1455
1456 trace("SSDO: %04X:%02X: received block upload request", sdo->idx,
1457 sdo->subidx);
1458
1459 // Load the number of segments per block.
1460 if (msg->len < 5)
1462 sdo->blksize = msg->data[4];
1463 if (!sdo->blksize || sdo->blksize > CO_SSDO_MAX_SEQNO)
1465
1466 // Load the protocol switch threshold (PST).
1467 co_unsigned8_t pst = msg->len > 5 ? msg->data[5] : 0;
1468
1469 // Perform access checks and start serializing the value.
1470 co_sdo_req_clear(&sdo->req);
1471 co_unsigned32_t ac = co_ssdo_up_ind(sdo);
1472 if (ac)
1473 return co_ssdo_abort_res(sdo, ac);
1474
1475 if (pst && sdo->req.size <= pst) {
1476 // If the PST is non-zero, and the number of bytes is smaller
1477 // than or equal to the PST, switch to the SDO upload protocol.
1478 if (sdo->req.size <= 4) {
1479 // Perform an expedited transfer.
1480 if ((ac = co_ssdo_up_buf(sdo, sdo->req.size)) != 0)
1481 return co_ssdo_abort_res(sdo, ac);
1483 return co_ssdo_abort_ind(sdo);
1484 } else {
1486 if (sdo->timeout)
1487 can_timer_timeout(sdo->timer, sdo->net,
1488 sdo->timeout);
1489 return co_ssdo_up_seg_state;
1490 }
1491 } else {
1493 if (sdo->timeout)
1494 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1496 }
1497}
1498
1499static co_ssdo_state_t *
1501{
1502 return co_ssdo_abort_res(sdo, ac);
1503}
1504
1505static co_ssdo_state_t *
1507{
1508 (void)tp;
1509
1511}
1512
1513static co_ssdo_state_t *
1515{
1516 assert(sdo);
1517 assert(msg);
1518
1519 if (msg->len < 1)
1521 co_unsigned8_t cs = msg->data[0];
1522
1523 // Check the client command specifier.
1524 switch (cs & CO_SDO_CS_MASK) {
1525 case CO_SDO_CCS_BLK_UP_REQ: break;
1526 case CO_SDO_CS_ABORT: return co_ssdo_abort_ind(sdo);
1527 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1528 }
1529
1530 // Check the client subcommand.
1531 switch (cs & CO_SDO_SC_MASK) {
1532 case CO_SDO_SC_BLK_RES:
1533 if (co_sdo_req_first(&sdo->req) && !sdo->nbyte)
1535
1536 if (msg->len < 3)
1538
1539 // Flush the successfully sent segments from the buffer.
1540 co_unsigned8_t ackseq = msg->data[1];
1541 membuf_flush(&sdo->buf, ackseq * 7);
1542
1543 // Read the number of segments in the next block.
1544 sdo->blksize = msg->data[2];
1545 if (!sdo->blksize || sdo->blksize > CO_SSDO_MAX_SEQNO)
1547
1548 break;
1549 case CO_SDO_SC_START_UP:
1550 if (!(co_sdo_req_first(&sdo->req) && !sdo->nbyte))
1552 break;
1553 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1554 }
1555
1556 ptrdiff_t n = sdo->blksize * 7 - membuf_size(&sdo->buf);
1557 if (n > 0) {
1558 if (!membuf_reserve(&sdo->buf, n))
1560 co_unsigned32_t ac = co_ssdo_up_buf(sdo, n);
1561 if (ac)
1562 return co_ssdo_abort_res(sdo, ac);
1563 sdo->blksize = (co_unsigned8_t)(
1564 (membuf_size(&sdo->buf) + 6) / 7);
1565 }
1566 int last = co_sdo_req_last(&sdo->req) && sdo->nbyte == sdo->req.nbyte;
1567
1568 if (sdo->timeout)
1569 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1570
1571 if (sdo->blksize) {
1572 // Send all segments in the current block.
1573 co_ssdo_send_blk_up_sub_res(sdo, last);
1575 } else {
1578 }
1579}
1580
1581static co_ssdo_state_t *
1583{
1584 return co_ssdo_abort_res(sdo, ac);
1585}
1586
1587static co_ssdo_state_t *
1589{
1590 (void)tp;
1591
1593}
1594
1595static co_ssdo_state_t *
1597{
1598 assert(sdo);
1599 assert(msg);
1600
1601 if (msg->len < 1)
1603 co_unsigned8_t cs = msg->data[0];
1604
1605 // Check the client command specifier.
1606 switch (cs & CO_SDO_CS_MASK) {
1607 case CO_SDO_CCS_BLK_UP_REQ: break;
1608 case CO_SDO_CS_ABORT: return co_ssdo_abort_ind(sdo);
1609 default: return co_ssdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1610 }
1611
1612 // Check the client subcommand.
1613 if ((cs & CO_SDO_SC_MASK) != CO_SDO_SC_END_BLK)
1615
1616 return co_ssdo_abort_ind(sdo);
1617}
1618
1619#endif // !LELY_NO_CO_SSDO_BLK
1620
1621static co_ssdo_state_t *
1623{
1624 assert(sdo);
1625
1626 if (sdo->timeout)
1627 can_timer_stop(sdo->timer);
1628
1629 sdo->idx = 0;
1630 sdo->subidx = 0;
1631
1632 sdo->toggle = 0;
1633#if !LELY_NO_CO_SSDO_BLK
1634 sdo->blksize = 0;
1635 sdo->ackseq = 0;
1636 sdo->gencrc = 0;
1637 sdo->crc = 0;
1638#endif
1639
1640 co_sdo_req_clear(&sdo->req);
1641 membuf_clear(&sdo->buf);
1642 sdo->nbyte = 0;
1643
1644 return co_ssdo_wait_state;
1645}
1646
1647static co_ssdo_state_t *
1648co_ssdo_abort_res(co_ssdo_t *sdo, co_unsigned32_t ac)
1649{
1650#if !LELY_NO_STDIO
1651 trace("SSDO: abort code %08" PRIX32 " (%s)", ac, co_sdo_ac2str(ac));
1652#endif
1653 co_ssdo_send_abort(sdo, ac);
1654 return co_ssdo_abort_ind(sdo);
1655}
1656
1657static co_unsigned32_t
1659{
1660 assert(sdo);
1661
1662 // Find the object in the object dictionary.
1663 co_obj_t *obj = co_dev_find_obj(sdo->dev, sdo->idx);
1664 if (!obj)
1665 return CO_SDO_AC_NO_OBJ;
1666
1667 // Find the sub-object.
1668 co_sub_t *sub = co_obj_find_sub(obj, sdo->subidx);
1669 if (!sub)
1670 return CO_SDO_AC_NO_SUB;
1671
1672 return co_sub_dn_ind(sub, &sdo->req);
1673}
1674
1675static co_unsigned32_t
1677{
1678 assert(sdo);
1679
1680 // Find the object in the object dictionary.
1681 const co_obj_t *obj = co_dev_find_obj(sdo->dev, sdo->idx);
1682 if (!obj)
1683 return CO_SDO_AC_NO_OBJ;
1684
1685 // Find the sub-object.
1686 const co_sub_t *sub = co_obj_find_sub(obj, sdo->subidx);
1687 if (!sub)
1688 return CO_SDO_AC_NO_SUB;
1689
1690 // If the object is an array, check whether the element exists.
1692 && sdo->subidx > co_obj_get_val_u8(obj, 0x00))
1693 return CO_SDO_AC_NO_DATA;
1694
1695 sdo->nbyte = 0;
1696 return co_sub_up_ind(sub, &sdo->req);
1697}
1698
1699static co_unsigned32_t
1700co_ssdo_up_buf(co_ssdo_t *sdo, size_t nbyte)
1701{
1702 co_unsigned32_t ac = 0;
1703
1704 if (nbyte && !membuf_reserve(&sdo->buf, nbyte))
1705 return CO_SDO_AC_NO_MEM;
1706
1707 while (nbyte) {
1708 if (sdo->nbyte >= sdo->req.nbyte) {
1709 if (co_sdo_req_last(&sdo->req)
1710 || (ac = co_ssdo_up_ind(sdo)))
1711 break;
1712 sdo->nbyte = 0;
1713 }
1714 const uint_least8_t *src = (const uint_least8_t *)sdo->req.buf
1715 + sdo->nbyte;
1716 size_t n = MIN(nbyte, sdo->req.nbyte - sdo->nbyte);
1717
1718#if !LELY_NO_CO_SSDO_BLK
1719 if (sdo->gencrc)
1720 sdo->crc = co_crc(sdo->crc, src, n);
1721#endif
1722
1723 membuf_write(&sdo->buf, src, n);
1724 nbyte -= n;
1725 sdo->nbyte += n;
1726 }
1727
1728 return ac;
1729}
1730
1731static void
1732co_ssdo_send_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
1733{
1734 assert(sdo);
1735
1736 struct can_msg msg;
1738 stle_u32(msg.data + 4, ac);
1739 can_net_send(sdo->net, &msg);
1740}
1741
1742static void
1744{
1745 assert(sdo);
1746
1747 co_unsigned8_t cs = CO_SDO_SCS_DN_INI_RES;
1748
1749 struct can_msg msg;
1750 co_ssdo_init_ini_res(sdo, &msg, cs);
1751 can_net_send(sdo->net, &msg);
1752}
1753
1754static void
1756{
1757 assert(sdo);
1758
1759 co_unsigned8_t cs = CO_SDO_SCS_DN_SEG_RES | sdo->toggle;
1760 sdo->toggle ^= CO_SDO_SEG_TOGGLE;
1761
1762 struct can_msg msg;
1763 co_ssdo_init_seg_res(sdo, &msg, cs);
1764 can_net_send(sdo->net, &msg);
1765}
1766
1767static void
1769{
1770 assert(sdo);
1771 assert(sdo->req.size && sdo->req.size <= 4);
1772
1773 const char *buf = membuf_begin(&sdo->buf);
1774 size_t nbyte = membuf_size(&sdo->buf);
1775 assert(nbyte == sdo->req.size);
1776
1777 co_unsigned8_t cs =
1779
1780 struct can_msg msg;
1781 co_ssdo_init_ini_res(sdo, &msg, cs);
1782 memcpy(msg.data + 4, buf, nbyte);
1783 can_net_send(sdo->net, &msg);
1784}
1785
1786static void
1788{
1789 assert(sdo);
1790 assert(!sdo->req.size || sdo->req.size > 4);
1791
1792 co_unsigned8_t cs = CO_SDO_SCS_UP_INI_RES | CO_SDO_INI_SIZE_IND;
1793
1794 struct can_msg msg;
1795 co_ssdo_init_ini_res(sdo, &msg, cs);
1796 stle_u32(msg.data + 4, sdo->req.size);
1797 can_net_send(sdo->net, &msg);
1798}
1799
1800static void
1802{
1803 assert(sdo);
1804 assert(!sdo->req.size || sdo->req.size > 4);
1805
1806 const char *buf = membuf_begin(&sdo->buf);
1807 size_t nbyte = membuf_size(&sdo->buf);
1808 assert(nbyte <= 7);
1809
1810 co_unsigned8_t cs = CO_SDO_SCS_UP_SEG_RES | sdo->toggle
1811 | CO_SDO_SEG_SIZE_SET(nbyte);
1812 sdo->toggle ^= CO_SDO_SEG_TOGGLE;
1813 if (last)
1814 cs |= CO_SDO_SEG_LAST;
1815
1816 struct can_msg msg;
1817 co_ssdo_init_seg_res(sdo, &msg, cs);
1818 memcpy(msg.data + 1, buf, nbyte);
1819 can_net_send(sdo->net, &msg);
1820}
1821
1822#if !LELY_NO_CO_SSDO_BLK
1823
1824static void
1826{
1827 assert(sdo);
1828
1829 co_unsigned8_t cs = CO_SDO_SCS_BLK_DN_RES | CO_SDO_SC_INI_BLK;
1830 if (sdo->gencrc)
1831 cs |= CO_SDO_BLK_CRC;
1832
1833 struct can_msg msg;
1834 co_ssdo_init_ini_res(sdo, &msg, cs);
1835 msg.data[4] = sdo->blksize;
1836 can_net_send(sdo->net, &msg);
1837}
1838
1839static void
1841{
1842 assert(sdo);
1843
1844 co_unsigned8_t cs = CO_SDO_SCS_BLK_DN_RES | CO_SDO_SC_BLK_RES;
1845
1846 struct can_msg msg;
1847 co_ssdo_init_seg_res(sdo, &msg, cs);
1848 msg.data[1] = sdo->ackseq;
1849 msg.data[2] = sdo->blksize;
1850 can_net_send(sdo->net, &msg);
1851}
1852
1853static void
1855{
1856 assert(sdo);
1857
1858 co_unsigned8_t cs = CO_SDO_SCS_BLK_DN_RES | CO_SDO_SC_END_BLK;
1859
1860 struct can_msg msg;
1861 co_ssdo_init_seg_res(sdo, &msg, cs);
1862 can_net_send(sdo->net, &msg);
1863}
1864
1865static void
1867{
1868 assert(sdo);
1869
1870 co_unsigned8_t cs = CO_SDO_SCS_BLK_UP_RES | CO_SDO_BLK_SIZE_IND
1872 if (sdo->gencrc)
1873 cs |= CO_SDO_BLK_CRC;
1874
1875 struct can_msg msg;
1876 co_ssdo_init_ini_res(sdo, &msg, cs);
1877 stle_u32(msg.data + 4, sdo->req.size);
1878 can_net_send(sdo->net, &msg);
1879}
1880
1881static void
1883{
1884 assert(sdo);
1885
1886 const char *buf = membuf_begin(&sdo->buf);
1887 size_t nbyte = membuf_size(&sdo->buf);
1888
1889 for (co_unsigned8_t seqno = 1; seqno <= sdo->blksize;
1890 seqno++, buf += 7, nbyte -= 7) {
1891 co_unsigned8_t cs = seqno;
1892 if (last && nbyte <= 7)
1893 cs |= CO_SDO_SEQ_LAST;
1894
1895 struct can_msg msg;
1896 co_ssdo_init_seg_res(sdo, &msg, cs);
1897 memcpy(msg.data + 1, buf, MIN(nbyte, 7));
1898 can_net_send(sdo->net, &msg);
1899 }
1900}
1901
1902static void
1904{
1905 assert(sdo);
1906
1907 // Compute the number of bytes in the last segment containing data.
1908 co_unsigned8_t n = sdo->req.size ? (sdo->req.size - 1) % 7 + 1 : 0;
1909
1910 co_unsigned8_t cs = CO_SDO_SCS_BLK_UP_RES | CO_SDO_SC_END_BLK
1912
1913 struct can_msg msg;
1914 co_ssdo_init_seg_res(sdo, &msg, cs);
1915 stle_u16(msg.data + 1, sdo->crc);
1916 can_net_send(sdo->net, &msg);
1917}
1918
1919#endif // !LELY_NO_CO_SSDO_BLK
1920
1921static void
1922co_ssdo_init_ini_res(co_ssdo_t *sdo, struct can_msg *msg, co_unsigned8_t cs)
1923{
1924 assert(sdo);
1925 assert(msg);
1926
1927 *msg = (struct can_msg)CAN_MSG_INIT;
1928 msg->id = sdo->par.cobid_res;
1929 if (sdo->par.cobid_res & CO_SDO_COBID_FRAME) {
1930 msg->id &= CAN_MASK_EID;
1931 msg->flags |= CAN_FLAG_IDE;
1932 } else {
1933 msg->id &= CAN_MASK_BID;
1934 }
1935 msg->len = CAN_MAX_LEN;
1936 msg->data[0] = cs;
1937 stle_u16(msg->data + 1, sdo->idx);
1938 msg->data[3] = sdo->subidx;
1939}
1940
1941static void
1942co_ssdo_init_seg_res(co_ssdo_t *sdo, struct can_msg *msg, co_unsigned8_t cs)
1943{
1944 assert(sdo);
1945 assert(msg);
1946
1947 *msg = (struct can_msg)CAN_MSG_INIT;
1948 msg->id = sdo->par.cobid_res;
1949 if (sdo->par.cobid_res & CO_SDO_COBID_FRAME) {
1950 msg->id &= CAN_MASK_EID;
1951 msg->flags |= CAN_FLAG_IDE;
1952 } else {
1953 msg->id &= CAN_MASK_BID;
1954 }
1955 msg->len = CAN_MAX_LEN;
1956 msg->data[0] = cs;
1957}
#define CAN_MASK_EID
The mask used to extract the 29-bit Extended Identifier from a CAN frame.
Definition msg.h:34
#define CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
Definition msg.h:72
@ CAN_FLAG_IDE
The Identifier Extension (IDE) flag.
Definition msg.h:43
@ CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames).
Definition msg.h:48
#define CAN_MASK_BID
The mask used to extract the 11-bit Base Identifier from a CAN frame.
Definition msg.h:31
#define CAN_MSG_INIT
The static initializer for can_msg.
Definition msg.h:113
This header file is part of the CANopen library; it contains the device description declarations.
co_obj_t * co_dev_find_obj(const co_dev_t *dev, co_unsigned16_t idx)
Finds an object in the object dictionary of a CANopen device.
Definition dev.c:279
co_unsigned8_t co_dev_get_id(const co_dev_t *dev)
Returns the node-ID of a CANopen device.
Definition dev.c:197
This header file is part of the CANopen library; it contains the Cyclic Redundancy Check (CRC) declar...
uint_least16_t co_crc(uint_least16_t crc, const uint_least8_t *bp, size_t n)
Computes a CRC-16 checksum.
Definition crc.c:28
This header file is part of the utilities library; it contains the byte order (endianness) function d...
uint_least32_t ldle_u32(const uint_least8_t src[4])
Loads a 32-bit unsigned integer in little-endian byte order.
Definition endian.h:596
uint_least16_t ldle_u16(const uint_least8_t src[2])
Loads a 16-bit unsigned integer in little-endian byte order.
Definition endian.h:516
void stle_u16(uint_least8_t dst[2], uint_least16_t x)
Stores a 16-bit unsigned integer in little-endian byte order.
Definition endian.h:504
void stle_u32(uint_least8_t dst[4], uint_least32_t x)
Stores a 32-bit unsigned integer in little-endian byte order.
Definition endian.h:582
This header file is part of the utilities library; it contains the native and platform-independent er...
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition errnum.c:810
@ ERRNUM_INVAL
Invalid argument.
Definition errnum.h:132
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition errnum.c:932
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition errnum.c:944
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition errnum.c:46
struct __co_ssdo co_ssdo_t
An opaque CANopen Server-SDO service type.
Definition co.h:67
struct __co_sub co_sub_t
An opaque CANopen sub-object type.
Definition co.h:56
struct __co_obj co_obj_t
An opaque CANopen object type.
Definition co.h:45
struct __co_dev co_dev_t
An opaque CANopen device type.
Definition co.h:34
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:343
#define CO_SDO_AC_TYPE_LEN_LO
SDO abort code: Data type does not match, length of service parameter too low.
Definition sdo.h:129
int co_sdo_req_dn_val(struct co_sdo_req *req, co_unsigned16_t type, void *val, co_unsigned32_t *pac)
Copies the next segment of the specified CANopen SDO download request to the internal buffer and,...
Definition sdo.c:170
#define CO_SDO_AC_TOGGLE
SDO abort code: Toggle bit not altered.
Definition sdo.h:63
#define CO_SDO_AC_TYPE_LEN_HI
SDO abort code: Data type does not match, length of service parameter too high.
Definition sdo.h:123
#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_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:349
#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_NUM_SDOS
The maximum number of Client/Server-SDOs.
Definition sdo.h:178
#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:161
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:52
void membuf_fini(struct membuf *buf)
Finalizes a memory buffer.
Definition membuf.c:40
void membuf_flush(struct membuf *buf, size_t size)
Flushes size bytes from the beginning of a memory buffer.
Definition membuf.c:88
void membuf_init(struct membuf *buf, void *ptr, size_t size)
Initializes a memory buffer.
Definition membuf.h:151
size_t membuf_write(struct membuf *buf, const void *ptr, size_t size)
Writes data to a memory buffer.
Definition membuf.h:222
void membuf_clear(struct membuf *buf)
Clears a memory buffer.
Definition membuf.h:169
size_t membuf_size(const struct membuf *buf)
Returns the total number of bytes written to a memory buffer.
Definition membuf.h:177
void can_timer_stop(can_timer_t *timer)
Stops a CAN timer and unregisters it with a network interface.
Definition net.c:462
int can_net_send(can_net_t *net, const struct can_msg *msg)
Sends a CAN frame from a network interface.
Definition net.c:300
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition net.c:376
void can_timer_set_func(can_timer_t *timer, can_timer_func_t *func, void *data)
Sets the callback function invoked when a CAN timer is triggered.
Definition net.c:422
void can_recv_stop(can_recv_t *recv)
Stops a CAN frame receiver from processing frames and unregisters it with the network interface.
Definition net.c:609
void can_recv_set_func(can_recv_t *recv, can_recv_func_t *func, void *data)
Sets the callback function used to process CAN frames with a receiver.
Definition net.c:578
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition net.c:558
struct __can_net can_net_t
An opaque CAN network interface type.
Definition net.h:31
void can_timer_timeout(can_timer_t *timer, can_net_t *net, int timeout)
Starts a CAN timer and registers it with a network interface.
Definition net.c:478
struct __can_timer can_timer_t
An opaque CAN timer type.
Definition net.h:37
struct __can_recv can_recv_t
An opaque CAN frame receiver type.
Definition net.h:43
void can_recv_start(can_recv_t *recv, can_net_t *net, uint_least32_t id, uint_least8_t flags)
Registers a CAN frame receiver with a network interface and starts processing frames.
Definition net.c:587
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition net.c:533
void can_timer_destroy(can_timer_t *timer)
Destroys a CAN timer.
Definition net.c:401
This header file is part of the CANopen library; it contains the object dictionary declarations.
co_unsigned8_t co_sub_get_subidx(const co_sub_t *sub)
Returns the sub-index of a CANopen sub-object.
Definition obj.c:559
co_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:958
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition obj.c:164
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:1066
co_sub_t * co_obj_find_sub(const co_obj_t *obj, co_unsigned8_t subidx)
Finds a sub-object in a CANopen object.
Definition obj.c:240
int co_sub_dn(co_sub_t *sub, void *val)
Downloads (moves) a value into a CANopen sub-object if the refuse-write-on-download flag (CO_OBJ_FLAG...
Definition obj.c:996
co_unsigned8_t co_obj_get_code(const co_obj_t *obj)
Returns the object code of a CANopen object.
Definition obj.c:303
#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:389
co_obj_t * co_sub_get_obj(const co_sub_t *sub)
Returns the a pointer to the CANopen object containing the specified sub-object.
Definition obj.c:551
co_unsigned16_t co_sub_get_type(const co_sub_t *sub)
Returns the data type of a CANopen sub-object.
Definition obj.c:603
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_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
int co_ssdo_start(co_ssdo_t *sdo)
Starts a Server-SDO service.
Definition ssdo.c:707
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:1009
void co_ssdo_stop(co_ssdo_t *sdo)
Stops a Server-SDO service.
Definition ssdo.c:741
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:1018
static void co_ssdo_send_blk_up_ini_res(co_ssdo_t *sdo)
Sends a Server-SDO 'block upload initiate' response.
Definition ssdo.c:1866
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:1203
void co_ssdo_destroy(co_ssdo_t *ssdo)
Destroys a CANopen Server-SDO service.
Definition ssdo.c:697
static void co_ssdo_send_dn_seg_res(co_ssdo_t *sdo)
Sends a Server-SDO 'download segment' response.
Definition ssdo.c:1755
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:1211
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:1372
co_unsigned8_t co_ssdo_get_num(const co_ssdo_t *sdo)
Returns the SDO number of a Server-SDO.
Definition ssdo.c:788
static co_ssdo_state_t *const co_ssdo_blk_dn_end_state
The 'block download end' state.
Definition ssdo.c:359
static void co_ssdo_init_ini_res(co_ssdo_t *sdo, struct can_msg *msg, co_unsigned8_t cs)
Initializes a Server-SDO download/upload initiate response CAN frame.
Definition ssdo.c:1922
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:1882
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:1306
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:1386
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:1676
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:1100
static void co_ssdo_send_blk_up_end_res(co_ssdo_t *sdo)
Sends a Server-SDO 'block upload end' response.
Definition ssdo.c:1903
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:1596
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:1500
static void co_ssdo_send_up_seg_res(co_ssdo_t *sdo, int last)
Sends a Server-SDO 'upload segment' response.
Definition ssdo.c:1801
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:1658
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:1840
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:1314
void co_ssdo_set_timeout(co_ssdo_t *sdo, int timeout)
Sets the timeout of a Server-SDO.
Definition ssdo.c:812
static int co_ssdo_update(co_ssdo_t *sdo)
Updates and (de)activates a Server-SDO service.
Definition ssdo.c:823
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:796
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:989
static co_ssdo_state_t *const co_ssdo_blk_up_sub_state
The 'block upload sub-block' state.
Definition ssdo.c:395
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:850
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:1252
static co_ssdo_state_t *const co_ssdo_blk_up_end_state
The 'block upload end' state.
Definition ssdo.c:418
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:936
static int co_ssdo_timer(const struct timespec *tp, void *data)
The CAN timer callback function for a Server-SDO service.
Definition ssdo.c:958
static co_ssdo_state_t *const co_ssdo_dn_seg_state
The 'download segment' state.
Definition ssdo.c:267
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:1160
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:1197
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:999
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:1700
static void co_ssdo_send_dn_ini_res(co_ssdo_t *sdo)
Sends a Server-SDO 'download initiate' response.
Definition ssdo.c:1743
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:670
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:1648
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:1040
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:772
static void co_ssdo_send_abort(co_ssdo_t *sdo, co_unsigned32_t ac)
Sends an abort transfer request.
Definition ssdo.c:1732
static void co_ssdo_send_blk_dn_end_res(co_ssdo_t *sdo)
Sends a Server-SDO 'block download end' response.
Definition ssdo.c:1854
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:1378
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:1094
static co_ssdo_state_t *const co_ssdo_blk_dn_sub_state
The 'block download sub-block' state.
Definition ssdo.c:335
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:1108
static void co_ssdo_init_seg_res(co_ssdo_t *sdo, struct can_msg *msg, co_unsigned8_t cs)
Initializes a Server-SDO download/upload segment response CAN frame.
Definition ssdo.c:1942
static void co_ssdo_send_blk_dn_ini_res(co_ssdo_t *sdo)
Sends a Server-SDO 'block download initiate' response.
Definition ssdo.c:1825
static co_ssdo_state_t *const co_ssdo_up_seg_state
The 'upload segment' state.
Definition ssdo.c:297
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:1506
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:1514
int co_ssdo_get_timeout(const co_ssdo_t *sdo)
Returns the timeout (in milliseconds) of a Server-SDO.
Definition ssdo.c:804
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:1582
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:1433
const struct __co_ssdo_state co_ssdo_state_t
An opaque CANopen Server-SDO state type.
Definition ssdo.c:68
static co_ssdo_state_t *const co_ssdo_stopped_state
The 'stopped' state.
Definition ssdo.c:217
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:780
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:1622
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:970
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:1300
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:1588
static void co_ssdo_send_up_exp_res(co_ssdo_t *sdo)
Sends a Server-SDO 'upload initiate' (expedited) response.
Definition ssdo.c:1768
static co_ssdo_state_t *const co_ssdo_wait_state
The 'waiting' state.
Definition ssdo.c:232
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:979
static void co_ssdo_send_up_ini_res(co_ssdo_t *sdo)
Sends a Server-SDO 'upload initiate' response.
Definition ssdo.c:1787
int co_ssdo_is_stopped(const co_ssdo_t *sdo)
Retuns 1 if the specified Server-SDO service is stopped, and 0 if not.
Definition ssdo.c:764
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....
This header file is part of the C11 and POSIX compatibility library; it includes <string....
A CANopen Server-SDO state.
Definition ssdo.c:181
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:200
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:210
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:191
A CANopen Server-SDO.
Definition ssdo.c:71
struct co_sdo_par par
The SDO parameter record.
Definition ssdo.c:79
co_unsigned16_t idx
The current object index.
Definition ssdo.c:89
co_ssdo_state_t * state
A pointer to the current state.
Definition ssdo.c:87
can_net_t * net
A pointer to a CAN network interface.
Definition ssdo.c:73
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition ssdo.c:81
int timeout
The SDO timeout (in milliseconds).
Definition ssdo.c:83
co_dev_t * dev
A pointer to a CANopen device.
Definition ssdo.c:75
unsigned gencrc
A flag indicating whether a CRC should be generated.
Definition ssdo.c:100
struct membuf buf
The buffer.
Definition ssdo.c:107
can_timer_t * timer
A pointer to the CAN timer.
Definition ssdo.c:85
co_unsigned16_t crc
The generated CRC.
Definition ssdo.c:102
co_unsigned8_t subidx
The current object sub-index.
Definition ssdo.c:91
struct co_sdo_req req
The SDO request.
Definition ssdo.c:105
co_unsigned8_t blksize
The number of segments per block.
Definition ssdo.c:96
co_unsigned8_t toggle
The current value of the toggle bit.
Definition ssdo.c:93
co_unsigned8_t num
The SDO number.
Definition ssdo.c:77
size_t nbyte
The number of bytes in req already copied to buf.
Definition ssdo.c:109
co_unsigned8_t ackseq
The sequence number of the last successfully received segment.
Definition ssdo.c:98
A CAN or CAN FD format frame.
Definition msg.h:87
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition msg.h:102
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition msg.h:89
uint_least8_t flags
The flags (any combination of CAN_FLAG_IDE, CAN_FLAG_RTR, CAN_FLAG_FDF, CAN_FLAG_BRS and CAN_FLAG_ESI...
Definition msg.h:94
uint_least8_t len
The number of bytes in data (or the requested number of bytes in case of a remote frame).
Definition msg.h:100
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:181
size_t offset
The offset of the bytes at buf.
Definition sdo.h:196
size_t size
The total size (in bytes) of the value to be uploaded/downloaded.
Definition sdo.h:187
const void * buf
A pointer to the next bytes to be uploaded/downloaded.
Definition sdo.h:189
size_t nbyte
The number of bytes available at buf.
Definition sdo.h:191
A memory buffer.
Definition membuf.h:36
A time type with nanosecond resolution.
Definition time.h:88
int co_type_is_array(co_unsigned16_t type)
Returns 1 if the specified (static) data type is an array, and 0 if not.
Definition type.c:40
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition type.h:44
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition type.h:50
A union of the CANopen static data types.
Definition val.h:273
This header file is part of the CANopen library; it contains the CANopen value declarations.