Lely core libraries 1.9.2
csdo.c
Go to the documentation of this file.
1
24#include "co.h"
25
26#ifndef LELY_NO_CO_CSDO
27
28#include "sdo.h"
29#include <lely/co/crc.h>
30#include <lely/co/csdo.h>
31#include <lely/co/dev.h>
32#include <lely/co/obj.h>
33#include <lely/co/val.h>
34#include <lely/util/endian.h>
35#include <lely/util/errnum.h>
36
37#include <assert.h>
38#include <stdlib.h>
39
40struct __co_csdo_state;
42typedef const struct __co_csdo_state co_csdo_state_t;
43
45struct __co_csdo {
51 co_unsigned8_t num;
63 co_unsigned32_t ac;
65 co_unsigned16_t idx;
67 co_unsigned8_t subidx;
69 uint32_t size;
71 uint8_t toggle;
73 uint8_t blksize;
75 uint8_t ackseq;
77 unsigned crc : 1;
79 struct membuf buf;
96};
97
104static int co_csdo_update(co_csdo_t *sdo);
105
112static co_unsigned32_t co_1280_dn_ind(
113 co_sub_t *sub, struct co_sdo_req *req, void *data);
114
120static int co_csdo_recv(const struct can_msg *msg, void *data);
121
127static int co_csdo_timer(const struct timespec *tp, void *data);
128
133static inline void co_csdo_enter(co_csdo_t *sdo, co_csdo_state_t *next);
134
142static inline void co_csdo_emit_abort(co_csdo_t *sdo, co_unsigned32_t ac);
143
151static inline void co_csdo_emit_time(co_csdo_t *sdo, const struct timespec *tp);
152
160static inline void co_csdo_emit_recv(co_csdo_t *sdo, const struct can_msg *msg);
161
165 co_csdo_state_t *(*on_enter)(co_csdo_t *sdo);
175 co_csdo_state_t *(*on_abort)(co_csdo_t *sdo, co_unsigned32_t ac);
184 co_csdo_state_t *(*on_time)(co_csdo_t *sdo, const struct timespec *tp);
194 co_csdo_state_t *(*on_recv)(co_csdo_t *sdo, const struct can_msg *msg);
196 void (*on_leave)(co_csdo_t *sdo);
197};
198
199#define LELY_CO_DEFINE_STATE(name, ...) \
200 static co_csdo_state_t *const name = &(co_csdo_state_t){ __VA_ARGS__ };
201
204 co_csdo_t *sdo, co_unsigned32_t ac);
205
208 co_csdo_t *sdo, const struct can_msg *msg);
209
211// clang-format off
212LELY_CO_DEFINE_STATE(co_csdo_wait_state,
213 .on_abort = &co_csdo_wait_on_abort,
214 .on_recv = &co_csdo_wait_on_recv
216// clang-format on
217
218
220
222static void co_csdo_abort_on_leave(co_csdo_t *sdo);
223
225// clang-format off
226LELY_CO_DEFINE_STATE(co_csdo_abort_state,
227 .on_enter = &co_csdo_abort_on_enter,
228 .on_leave = &co_csdo_abort_on_leave
230// clang-format on
231
234 co_csdo_t *sdo, co_unsigned32_t ac);
235
238 co_csdo_t *sdo, const struct timespec *tp);
239
245 co_csdo_t *sdo, const struct can_msg *msg);
246
248// clang-format off
249LELY_CO_DEFINE_STATE(co_csdo_dn_ini_state,
250 .on_abort = &co_csdo_dn_ini_on_abort,
251 .on_time = &co_csdo_dn_ini_on_time,
252 .on_recv = &co_csdo_dn_ini_on_recv
254// clang-format on
255
258
261 co_csdo_t *sdo, co_unsigned32_t ac);
262
265 co_csdo_t *sdo, const struct timespec *tp);
266
271 co_csdo_t *sdo, const struct can_msg *msg);
272
274// clang-format off
275LELY_CO_DEFINE_STATE(co_csdo_dn_seg_state,
276 .on_enter = &co_csdo_dn_seg_on_enter,
277 .on_abort = &co_csdo_dn_seg_on_abort,
278 .on_time = &co_csdo_dn_seg_on_time,
279 .on_recv = &co_csdo_dn_seg_on_recv
281// clang-format on
282
285 co_csdo_t *sdo, co_unsigned32_t ac);
286
289 co_csdo_t *sdo, const struct timespec *tp);
290
293 co_csdo_t *sdo, const struct can_msg *msg);
294
296// clang-format off
297LELY_CO_DEFINE_STATE(co_csdo_up_ini_state,
298 .on_abort = &co_csdo_up_ini_on_abort,
299 .on_time = &co_csdo_up_ini_on_time,
300 .on_recv = &co_csdo_up_ini_on_recv
302// clang-format on
303
306 co_csdo_t *sdo, co_unsigned32_t ac);
307
310 co_csdo_t *sdo, const struct timespec *tp);
311
314 co_csdo_t *sdo, const struct can_msg *msg);
315
317// clang-format off
318LELY_CO_DEFINE_STATE(co_csdo_up_seg_state,
319 .on_abort = &co_csdo_up_seg_on_abort,
320 .on_time = &co_csdo_up_seg_on_time,
321 .on_recv = &co_csdo_up_seg_on_recv
323// clang-format on
324
327 co_csdo_t *sdo, co_unsigned32_t ac);
328
331 co_csdo_t *sdo, const struct timespec *tp);
332
338 co_csdo_t *sdo, const struct can_msg *msg);
339
341// clang-format off
342LELY_CO_DEFINE_STATE(co_csdo_blk_dn_ini_state,
343 .on_abort = &co_csdo_blk_dn_ini_on_abort,
344 .on_time = &co_csdo_blk_dn_ini_on_time,
347// clang-format on
348
351
354 co_csdo_t *sdo, co_unsigned32_t ac);
355
358 co_csdo_t *sdo, const struct timespec *tp);
359
365 co_csdo_t *sdo, const struct can_msg *msg);
366
368// clang-format off
369LELY_CO_DEFINE_STATE(co_csdo_blk_dn_sub_state,
370 .on_enter = &co_csdo_blk_dn_sub_on_enter,
371 .on_abort = &co_csdo_blk_dn_sub_on_abort,
372 .on_time = &co_csdo_blk_dn_sub_on_time,
375// clang-format on
376
379 co_csdo_t *sdo, co_unsigned32_t ac);
380
383 co_csdo_t *sdo, const struct timespec *tp);
384
390 co_csdo_t *sdo, const struct can_msg *msg);
391
393// clang-format off
394LELY_CO_DEFINE_STATE(co_csdo_blk_dn_end_state,
395 .on_abort = &co_csdo_blk_dn_end_on_abort,
396 .on_time = &co_csdo_blk_dn_end_on_time,
399// clang-format on
400
403 co_csdo_t *sdo, co_unsigned32_t ac);
404
407 co_csdo_t *sdo, const struct timespec *tp);
408
414 co_csdo_t *sdo, const struct can_msg *msg);
415
417// clang-format off
418LELY_CO_DEFINE_STATE(co_csdo_blk_up_ini_state,
419 .on_abort = &co_csdo_blk_up_ini_on_abort,
420 .on_time = &co_csdo_blk_up_ini_on_time,
423// clang-format on
424
427 co_csdo_t *sdo, co_unsigned32_t ac);
428
431 co_csdo_t *sdo, const struct timespec *tp);
432
438 co_csdo_t *sdo, const struct can_msg *msg);
439
441// clang-format off
442LELY_CO_DEFINE_STATE(co_csdo_blk_up_sub_state,
443 .on_abort = &co_csdo_blk_up_sub_on_abort,
444 .on_time = &co_csdo_blk_up_sub_on_time,
447// clang-format on
448
451 co_csdo_t *sdo, co_unsigned32_t ac);
452
455 co_csdo_t *sdo, const struct timespec *tp);
456
461 co_csdo_t *sdo, const struct can_msg *msg);
462
464// clang-format off
465LELY_CO_DEFINE_STATE(co_csdo_blk_up_end_state,
466 .on_abort = &co_csdo_blk_up_end_on_abort,
467 .on_time = &co_csdo_blk_up_end_on_time,
470// clang-format on
471
472#undef LELY_CO_DEFINE_STATE
473
480static co_csdo_state_t *co_csdo_abort_ind(co_csdo_t *sdo, co_unsigned32_t ac);
481
493static co_csdo_state_t *co_csdo_abort_res(co_csdo_t *sdo, co_unsigned32_t ac);
494
503static int co_csdo_dn_ind(co_csdo_t *sdo, co_unsigned16_t idx,
504 co_unsigned8_t subidx, const void *ptr, size_t n,
505 co_csdo_dn_con_t *con, void *data);
506
515static int co_csdo_up_ind(co_csdo_t *sdo, co_unsigned16_t idx,
516 co_unsigned8_t subidx, co_csdo_up_con_t *con, void *data);
517
524static void co_csdo_send_abort(co_csdo_t *sdo, co_unsigned32_t ac);
525
527static void co_csdo_send_dn_exp_req(co_csdo_t *sdo);
528
530static void co_csdo_send_dn_ini_req(co_csdo_t *sdo);
531
540static void co_csdo_send_dn_seg_req(co_csdo_t *sdo, uint32_t n, int last);
541
543static void co_csdo_send_up_ini_req(co_csdo_t *sdo);
544
546static void co_csdo_send_up_seg_req(co_csdo_t *sdo);
547
549static void co_csdo_send_blk_dn_ini_req(co_csdo_t *sdo);
550
557static void co_csdo_send_blk_dn_sub_req(co_csdo_t *sdo, uint8_t seqno);
558
560static void co_csdo_send_blk_dn_end_req(co_csdo_t *sdo);
561
568static void co_csdo_send_blk_up_ini_req(co_csdo_t *sdo, uint8_t pst);
569
571static void co_csdo_send_start_up_req(co_csdo_t *sdo);
572
574static void co_csdo_send_blk_up_sub_res(co_csdo_t *sdo);
575
577static void co_csdo_send_blk_up_end_res(co_csdo_t *sdo);
578
586static void co_csdo_init_ini_req(
587 co_csdo_t *sdo, struct can_msg *msg, uint8_t cs);
588
596static void co_csdo_init_seg_req(
597 co_csdo_t *sdo, struct can_msg *msg, uint8_t cs);
598
599int
600co_dev_dn_req(co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx,
601 const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
602{
603 assert(dev);
604
605 int errc = get_errc();
606 struct co_sdo_req req = CO_SDO_REQ_INIT;
607
608 co_unsigned32_t ac = 0;
609
610 co_obj_t *obj = co_dev_find_obj(dev, idx);
611 if (__unlikely(!obj)) {
612 ac = CO_SDO_AC_NO_OBJ;
613 goto done;
614 }
615
616 co_sub_t *sub = co_obj_find_sub(obj, subidx);
617 if (__unlikely(!sub)) {
618 ac = CO_SDO_AC_NO_SUB;
619 goto done;
620 }
621
622 if (__unlikely(co_sdo_req_up(&req, ptr, n, &ac) == -1))
623 goto done;
624
625 ac = co_sub_dn_ind(sub, &req);
626
627done:
628 if (con)
629 con(NULL, idx, subidx, ac, data);
630
631 co_sdo_req_fini(&req);
632 set_errc(errc);
633 return 0;
634}
635
636int
637co_dev_dn_val_req(co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx,
638 co_unsigned16_t type, const void *val, co_csdo_dn_con_t *con,
639 void *data)
640{
641 assert(dev);
642
643 int errc = get_errc();
644 struct co_sdo_req req = CO_SDO_REQ_INIT;
645
646 co_unsigned32_t ac = 0;
647
648 co_obj_t *obj = co_dev_find_obj(dev, idx);
649 if (__unlikely(!obj)) {
650 ac = CO_SDO_AC_NO_OBJ;
651 goto done;
652 }
653
654 co_sub_t *sub = co_obj_find_sub(obj, subidx);
655 if (__unlikely(!sub)) {
656 ac = CO_SDO_AC_NO_SUB;
657 goto done;
658 }
659
660 if (__unlikely(co_sdo_req_up_val(&req, type, val, &ac) == -1))
661 goto done;
662
663 ac = co_sub_dn_ind(sub, &req);
664
665done:
666 if (con)
667 con(NULL, idx, subidx, ac, data);
668
669 co_sdo_req_fini(&req);
670 set_errc(errc);
671 return 0;
672}
673
674int
675co_dev_up_req(const co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx,
676 co_csdo_up_con_t *con, void *data)
677{
678 assert(dev);
679
680 int errc = get_errc();
681 struct membuf buf = MEMBUF_INIT;
682 co_unsigned32_t ac = 0;
683
684 const co_obj_t *obj = co_dev_find_obj(dev, idx);
685 if (__unlikely(!obj)) {
686 ac = CO_SDO_AC_NO_OBJ;
687 goto done;
688 }
689
690 const co_sub_t *sub = co_obj_find_sub(obj, subidx);
691 if (__unlikely(!sub)) {
692 ac = CO_SDO_AC_NO_SUB;
693 goto done;
694 }
695
696 // If the object is an array, check whether the element exists.
698 && __unlikely(subidx > co_obj_get_val_u8(obj, 0))) {
700 goto done;
701 }
702
703 struct co_sdo_req req = CO_SDO_REQ_INIT;
704
705 ac = co_sub_up_ind(sub, &req);
706 if (!ac && req.size && !membuf_reserve(&buf, req.size))
707 ac = CO_SDO_AC_NO_MEM;
708
709 do {
710 membuf_write(&buf, req.buf, req.nbyte);
711 if (!co_sdo_req_last(&req))
712 ac = co_sub_up_ind(sub, &req);
713 } while (!ac && membuf_size(&buf) < req.size);
714
715 co_sdo_req_fini(&req);
716
717done:
718 if (con)
719 con(NULL, idx, subidx, ac, ac ? NULL : buf.begin,
720 ac ? 0 : membuf_size(&buf), data);
721
723 set_errc(errc);
724 return 0;
725}
726
727void *
728__co_csdo_alloc(void)
729{
730 void *ptr = malloc(sizeof(struct __co_csdo));
731 if (__unlikely(!ptr))
732 set_errc(errno2c(errno));
733 return ptr;
734}
735
736void
737__co_csdo_free(void *ptr)
738{
739 free(ptr);
740}
741
742struct __co_csdo *
743__co_csdo_init(struct __co_csdo *sdo, can_net_t *net, co_dev_t *dev,
744 co_unsigned8_t num)
745{
746 assert(sdo);
747 assert(net);
748
749 int errc = 0;
750
751 if (__unlikely(!num || num > (dev ? 128 : CO_NUM_NODES))) {
752 errc = errnum2c(ERRNUM_INVAL);
753 goto error_param;
754 }
755
756 // Find the SDO client parameter in the object dictionary.
757 co_obj_t *obj_1280 =
758 dev ? co_dev_find_obj(dev, 0x1280 + num - 1) : NULL;
759 if (__unlikely(dev && !obj_1280)) {
760 errc = errnum2c(ERRNUM_INVAL);
761 goto error_param;
762 }
763
764 sdo->net = net;
765 sdo->dev = dev;
766 sdo->num = num;
767
768 // Initialize the SDO parameter record with the default values.
769 sdo->par.n = 3;
770 sdo->par.id = num;
771 sdo->par.cobid_req = 0x600 + sdo->par.id;
772 sdo->par.cobid_res = 0x580 + sdo->par.id;
773
774 if (obj_1280) {
775 // Copy the SDO parameter record.
776 size_t size = co_obj_sizeof_val(obj_1280);
777 memcpy(&sdo->par, co_obj_addressof_val(obj_1280),
778 MIN(size, sizeof(sdo->par)));
779 }
780
781 sdo->recv = can_recv_create();
782 if (__unlikely(!sdo->recv)) {
783 errc = get_errc();
784 goto error_create_recv;
785 }
787
788 sdo->timeout = 0;
789
790 sdo->timer = can_timer_create();
791 if (__unlikely(!sdo->timer)) {
792 errc = get_errc();
793 goto error_create_timer;
794 }
796
798
799 sdo->ac = 0;
800 sdo->idx = 0;
801 sdo->subidx = 0;
802 sdo->size = 0;
803
804 sdo->toggle = 0;
805 sdo->blksize = 0;
806 sdo->ackseq = 0;
807 sdo->crc = 0;
808
809 membuf_init(&sdo->buf);
810
811 sdo->dn_con = NULL;
812 sdo->dn_con_data = NULL;
813
814 sdo->dn_ind = NULL;
815 sdo->dn_ind_data = NULL;
816
817 sdo->up_con = NULL;
818 sdo->up_con_data = NULL;
819
820 sdo->up_ind = NULL;
821 sdo->up_ind_data = NULL;
822
823 // Set the download indication function for the SDO parameter record.
824 if (obj_1280)
825 co_obj_set_dn_ind(obj_1280, &co_1280_dn_ind, sdo);
826
827 if (__unlikely(co_csdo_update(sdo) == -1)) {
828 errc = get_errc();
829 goto error_update;
830 }
831
832 return sdo;
833
834error_update:
835 if (obj_1280)
836 co_obj_set_dn_ind(obj_1280, NULL, NULL);
838error_create_timer:
840error_create_recv:
841error_param:
842 set_errc(errc);
843 return NULL;
844}
845
846void
847__co_csdo_fini(struct __co_csdo *sdo)
848{
849 assert(sdo);
850 assert(sdo->num >= 1 && sdo->num <= 128);
851
852 // Remove the download indication functions for the SDO parameter
853 // record.
854 co_obj_t *obj_1280 = sdo->dev
855 ? co_dev_find_obj(sdo->dev, 0x1280 + sdo->num - 1)
856 : NULL;
857 if (obj_1280)
858 co_obj_set_dn_ind(obj_1280, NULL, NULL);
859
860 membuf_fini(&sdo->buf);
861
864}
865
866co_csdo_t *
868{
869 trace("creating Client-SDO %d", num);
870
871 int errc = 0;
872
873 co_csdo_t *sdo = __co_csdo_alloc();
874 if (__unlikely(!sdo)) {
875 errc = get_errc();
876 goto error_alloc_sdo;
877 }
878
879 if (__unlikely(!__co_csdo_init(sdo, net, dev, num))) {
880 errc = get_errc();
881 goto error_init_sdo;
882 }
883
884 return sdo;
885
886error_init_sdo:
887 __co_csdo_free(sdo);
888error_alloc_sdo:
889 set_errc(errc);
890 return NULL;
891}
892
893void
895{
896 if (csdo) {
897 trace("destroying Client-SDO %d", csdo->num);
898 __co_csdo_fini(csdo);
899 __co_csdo_free(csdo);
900 }
901}
902
903can_net_t *
905{
906 assert(sdo);
907
908 return sdo->net;
909}
910
911co_dev_t *
913{
914 assert(sdo);
915
916 return sdo->dev;
917}
918
919co_unsigned8_t
921{
922 assert(sdo);
923
924 return sdo->num;
925}
926
927const struct co_sdo_par *
929{
930 assert(sdo);
931
932 return &sdo->par;
933}
934
935int
937{
938 assert(sdo);
939
940 return sdo->timeout;
941}
942
943void
945{
946 assert(sdo);
947
948 if (sdo->timeout && timeout <= 0)
949 can_timer_stop(sdo->timer);
950
951 sdo->timeout = MAX(0, timeout);
952}
953
954void
955co_csdo_get_dn_ind(const co_csdo_t *sdo, co_csdo_ind_t **pind, void **pdata)
956{
957 assert(sdo);
958
959 if (pind)
960 *pind = sdo->dn_ind;
961 if (pdata)
962 *pdata = sdo->dn_ind_data;
963}
964
965void
967{
968 assert(sdo);
969
970 sdo->dn_ind = ind;
971 sdo->dn_ind_data = data;
972}
973
974void
975co_csdo_get_up_ind(const co_csdo_t *sdo, co_csdo_ind_t **pind, void **pdata)
976{
977 assert(sdo);
978
979 if (pind)
980 *pind = sdo->up_ind;
981 if (pdata)
982 *pdata = sdo->up_ind_data;
983}
984
985void
987{
988 assert(sdo);
989
990 sdo->up_ind = ind;
991 sdo->up_ind_data = data;
992}
993
994int
996{
997 assert(sdo);
998
999 return sdo->state == co_csdo_wait_state;
1000}
1001
1002void
1003co_csdo_abort_req(co_csdo_t *sdo, co_unsigned32_t ac)
1004{
1005 assert(sdo);
1006
1007 co_csdo_emit_abort(sdo, ac);
1008}
1009
1010int
1011co_csdo_dn_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1012 const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
1013{
1014 assert(sdo);
1015
1016 // clang-format off
1017 if (__unlikely(co_csdo_dn_ind(sdo, idx, subidx, ptr, n, con, data)
1018 == -1))
1019 // clang-format on
1020 return -1;
1021
1022 trace("CSDO: %04X:%02X: initiate download", idx, subidx);
1023
1024 if (sdo->timeout)
1025 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1026 if (sdo->size && sdo->size <= 4)
1028 else
1031
1032 return 0;
1033}
1034
1035int
1036co_csdo_dn_val_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1037 co_unsigned16_t type, const void *val, co_csdo_dn_con_t *con,
1038 void *data)
1039{
1040 assert(sdo);
1041
1042 // Obtain the size of the serialized value (which may be 0 for arrays).
1043 size_t n = co_val_write(type, val, NULL, NULL);
1044 if (__unlikely(!n && co_val_sizeof(type, val)))
1045 return -1;
1046
1047 if (co_type_is_array(type) || n > 8) {
1048 int res = 0;
1049 int errc = get_errc();
1050
1051 uint8_t *buf = n ? malloc(n) : NULL;
1052 if (__unlikely(n && !buf)) {
1053 errc = errno2c(errno);
1054 goto error_malloc_buf;
1055 }
1056
1057 if (__unlikely(co_val_write(type, val, buf, buf + n) != n)) {
1058 errc = get_errc();
1059 goto error_write_val;
1060 }
1061
1062 res = co_csdo_dn_req(sdo, idx, subidx, buf, n, con, data);
1063
1064 error_write_val:
1065 free(buf);
1066 error_malloc_buf:
1067 set_errc(errc);
1068 return res;
1069 } else {
1070 // Fast path for values small enough to be allocated on the
1071 // heap.
1072 uint8_t buf[8];
1073 if (__unlikely(co_val_write(type, val, buf, buf + n) != n))
1074 return -1;
1075 return co_csdo_dn_req(sdo, idx, subidx, buf, n, con, data);
1076 }
1077}
1078
1079int
1080co_csdo_up_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1081 co_csdo_up_con_t *con, void *data)
1082{
1083 assert(sdo);
1084
1085 if (__unlikely(co_csdo_up_ind(sdo, idx, subidx, con, data) == -1))
1086 return -1;
1087
1088 trace("CSDO: %04X:%02X: initiate upload", idx, subidx);
1089
1090 if (sdo->timeout)
1091 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1094
1095 return 0;
1096}
1097
1098int
1099co_csdo_blk_dn_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1100 const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
1101{
1102 assert(sdo);
1103
1104 // clang-format off
1105 if (__unlikely(co_csdo_dn_ind(sdo, idx, subidx, ptr, n, con, data)
1106 == -1))
1107 // clang-format on
1108 return -1;
1109
1110 trace("CSDO: %04X:%02X: initiate block download", idx, subidx);
1111
1112 if (sdo->timeout)
1113 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1116
1117 return 0;
1118}
1119
1120int
1121co_csdo_blk_up_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1122 uint8_t pst, co_csdo_up_con_t *con, void *data)
1123{
1124 assert(sdo);
1125
1126 if (__unlikely(co_csdo_up_ind(sdo, idx, subidx, con, data) == -1))
1127 return -1;
1128
1129 trace("CSDO: %04X:%02X: initiate block upload", idx, subidx);
1130
1131 // Use the maximum block size by default.
1133
1134 if (sdo->timeout)
1135 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1138
1139 return 0;
1140}
1141
1142static int
1144{
1145 assert(sdo);
1146
1147 // Abort any ongoing transfer.
1149
1150 int valid_req = !(sdo->par.cobid_req & CO_SDO_COBID_VALID);
1151 int valid_res = !(sdo->par.cobid_res & CO_SDO_COBID_VALID);
1152 if (valid_req && valid_res) {
1153 uint32_t id = sdo->par.cobid_res;
1154 uint8_t flags = 0;
1155 if (id & CO_SDO_COBID_FRAME) {
1156 id &= CAN_MASK_EID;
1157 flags |= CAN_FLAG_IDE;
1158 } else {
1159 id &= CAN_MASK_BID;
1160 }
1161 can_recv_start(sdo->recv, sdo->net, id, flags);
1162 } else {
1163 can_recv_stop(sdo->recv);
1164 }
1165
1166 return 0;
1167}
1168
1169static co_unsigned32_t
1170co_1280_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
1171{
1172 assert(sub);
1173 assert(req);
1174 co_csdo_t *sdo = data;
1175 assert(sdo);
1176 assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1280 + sdo->num - 1);
1177
1178 co_unsigned32_t ac = 0;
1179
1180 co_unsigned16_t type = co_sub_get_type(sub);
1181 union co_val val;
1182 if (__unlikely(co_sdo_req_dn_val(req, type, &val, &ac) == -1))
1183 return ac;
1184
1185 switch (co_sub_get_subidx(sub)) {
1186 case 0: ac = CO_SDO_AC_NO_WRITE; goto error;
1187 case 1: {
1188 assert(type == CO_DEFTYPE_UNSIGNED32);
1189 co_unsigned32_t cobid = val.u32;
1190 co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
1191 if (cobid == cobid_old)
1192 goto error;
1193
1194 // The CAN-ID cannot be changed when the SDO is and remains
1195 // valid.
1196 int valid = !(cobid & CO_SDO_COBID_VALID);
1197 int valid_old = !(cobid_old & CO_SDO_COBID_VALID);
1198 uint32_t canid = cobid & CAN_MASK_EID;
1199 uint32_t canid_old = cobid_old & CAN_MASK_EID;
1200 if (__unlikely(valid && valid_old && canid != canid_old)) {
1202 goto error;
1203 }
1204
1205 // A 29-bit CAN-ID is only valid if the frame bit is set.
1206 // clang-format off
1207 if (__unlikely(!(cobid & CO_SDO_COBID_FRAME)
1208 && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))) {
1209 // clang-format on
1211 goto error;
1212 }
1213
1214 sdo->par.cobid_req = cobid;
1215 break;
1216 }
1217 case 2: {
1218 assert(type == CO_DEFTYPE_UNSIGNED32);
1219 co_unsigned32_t cobid = val.u32;
1220 co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
1221 if (cobid == cobid_old)
1222 goto error;
1223
1224 // The CAN-ID cannot be changed when the SDO is and remains
1225 // valid.
1226 int valid = !(cobid & CO_SDO_COBID_VALID);
1227 int valid_old = !(cobid_old & CO_SDO_COBID_VALID);
1228 uint32_t canid = cobid & CAN_MASK_EID;
1229 uint32_t canid_old = cobid_old & CAN_MASK_EID;
1230 if (__unlikely(valid && valid_old && canid != canid_old)) {
1232 goto error;
1233 }
1234
1235 // A 29-bit CAN-ID is only valid if the frame bit is set.
1236 // clang-format off
1237 if (__unlikely(!(cobid & CO_SDO_COBID_FRAME)
1238 && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))) {
1239 // clang-format on
1241 goto error;
1242 }
1243
1244 sdo->par.cobid_res = cobid;
1245 break;
1246 }
1247 case 3: {
1248 assert(type == CO_DEFTYPE_UNSIGNED8);
1249 co_unsigned8_t id = val.u8;
1250 co_unsigned8_t id_old = co_sub_get_val_u8(sub);
1251 if (id == id_old)
1252 goto error;
1253
1254 sdo->par.id = id;
1255 break;
1256 }
1257 default: ac = CO_SDO_AC_NO_SUB; goto error;
1258 }
1259
1260 co_sub_dn(sub, &val);
1261 co_val_fini(type, &val);
1262
1263 co_csdo_update(sdo);
1264 return 0;
1265
1266error:
1267 co_val_fini(type, &val);
1268 return ac;
1269}
1270
1271static int
1272co_csdo_recv(const struct can_msg *msg, void *data)
1273{
1274 assert(msg);
1275 co_csdo_t *sdo = data;
1276 assert(sdo);
1277
1278 // Ignore remote frames.
1279 if (__unlikely(msg->flags & CAN_FLAG_RTR))
1280 return 0;
1281
1282#ifndef LELY_NO_CANFD
1283 // Ignore CAN FD format frames.
1284 if (__unlikely(msg->flags & CAN_FLAG_EDL))
1285 return 0;
1286#endif
1287
1288 co_csdo_emit_recv(sdo, msg);
1289
1290 return 0;
1291}
1292
1293static int
1294co_csdo_timer(const struct timespec *tp, void *data)
1295{
1296 assert(tp);
1297 co_csdo_t *sdo = data;
1298 assert(sdo);
1299
1300 co_csdo_emit_time(sdo, tp);
1301
1302 return 0;
1303}
1304
1305static inline void
1307{
1308 assert(sdo);
1309 assert(sdo->state);
1310
1311 while (next) {
1312 co_csdo_state_t *prev = sdo->state;
1313 sdo->state = next;
1314
1315 if (prev->on_leave)
1316 prev->on_leave(sdo);
1317
1318 next = next->on_enter ? next->on_enter(sdo) : NULL;
1319 }
1320}
1321
1322static inline void
1323co_csdo_emit_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1324{
1325 assert(sdo);
1326 assert(sdo->state);
1327 assert(sdo->state->on_abort);
1328
1329 co_csdo_enter(sdo, sdo->state->on_abort(sdo, ac));
1330}
1331
1332static inline void
1333co_csdo_emit_time(co_csdo_t *sdo, const struct timespec *tp)
1334{
1335 assert(sdo);
1336 assert(sdo->state);
1337 assert(sdo->state->on_time);
1338
1339 co_csdo_enter(sdo, sdo->state->on_time(sdo, tp));
1340}
1341
1342static inline void
1343co_csdo_emit_recv(co_csdo_t *sdo, const struct can_msg *msg)
1344{
1345 assert(sdo);
1346 assert(sdo->state);
1347 assert(sdo->state->on_recv);
1348
1349 co_csdo_enter(sdo, sdo->state->on_recv(sdo, msg));
1350}
1351
1352static co_csdo_state_t *
1353co_csdo_wait_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1354{
1355 (void)sdo;
1356 (void)ac;
1357
1358 return NULL;
1359}
1360
1361static co_csdo_state_t *
1363{
1364 assert(sdo);
1365 assert(msg);
1366
1367 if (__unlikely(msg->len < 1))
1369 uint8_t cs = msg->data[0];
1370
1371 co_unsigned32_t ac;
1372 switch (cs & CO_SDO_CS_MASK) {
1373 case CO_SDO_CS_ABORT:
1374 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1375 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1376 default: return NULL;
1377 }
1378}
1379
1380static co_csdo_state_t *
1382{
1383 (void)sdo;
1384
1385 can_timer_stop(sdo->timer);
1386
1387 return co_csdo_wait_state;
1388}
1389
1390static void
1392{
1393 assert(sdo);
1394
1395 co_csdo_dn_con_t *dn_con = sdo->dn_con;
1396 sdo->dn_con = NULL;
1397 void *dn_con_data = sdo->dn_con_data;
1398 sdo->dn_con_data = NULL;
1399
1400 co_csdo_up_con_t *up_con = sdo->up_con;
1401 sdo->up_con = NULL;
1402 void *up_con_data = sdo->up_con_data;
1403 sdo->up_con_data = NULL;
1404
1405 if (dn_con) {
1406 dn_con(sdo, sdo->idx, sdo->subidx, sdo->ac, dn_con_data);
1407 } else if (up_con) {
1408 up_con(sdo, sdo->idx, sdo->subidx, sdo->ac,
1409 sdo->ac ? NULL : sdo->buf.begin,
1410 sdo->ac ? 0 : membuf_size(&sdo->buf),
1411 up_con_data);
1412 }
1413}
1414
1415static co_csdo_state_t *
1416co_csdo_dn_ini_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1417{
1418 return co_csdo_abort_res(sdo, ac);
1419}
1420
1421static co_csdo_state_t *
1423{
1424 (void)tp;
1425
1427}
1428
1429static co_csdo_state_t *
1431{
1432 assert(sdo);
1433 assert(msg);
1434
1435 if (__unlikely(msg->len < 1))
1437 uint8_t cs = msg->data[0];
1438
1439 // Check the server command specifier.
1440 co_unsigned32_t ac;
1441 switch (cs & CO_SDO_CS_MASK) {
1442 case CO_SDO_SCS_DN_INI_RES: break;
1443 case CO_SDO_CS_ABORT:
1444 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1445 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1446 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1447 }
1448
1449 // Check the object index and sub-index.
1450 if (__unlikely(msg->len < 4))
1452 co_unsigned16_t idx = ldle_u16(msg->data + 1);
1453 co_unsigned8_t subidx = msg->data[3];
1454 if (__unlikely(idx != sdo->idx || subidx != sdo->subidx))
1456
1457 return co_csdo_dn_seg_state;
1458}
1459
1460static co_csdo_state_t *
1462{
1463 assert(sdo);
1464
1465 size_t n = sdo->size - membuf_size(&sdo->buf);
1466 // 0-byte values cannot be sent using expedited transfer, so we need to
1467 // send one empty segment. We use the toggle bit to check if it was
1468 // sent.
1469 if (n || (!sdo->size && !sdo->toggle)) {
1470 if (sdo->timeout)
1471 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1472 co_csdo_send_dn_seg_req(sdo, MIN(n, 7), n <= 7);
1473 return NULL;
1474 } else {
1475 return co_csdo_abort_ind(sdo, 0);
1476 }
1477}
1478
1479static co_csdo_state_t *
1480co_csdo_dn_seg_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1481{
1482 return co_csdo_abort_res(sdo, ac);
1483}
1484
1485static co_csdo_state_t *
1487{
1488 (void)tp;
1489
1491}
1492
1493static co_csdo_state_t *
1495{
1496 assert(sdo);
1497 assert(msg);
1498
1499 if (__unlikely(msg->len < 1))
1501 uint8_t cs = msg->data[0];
1502
1503 // Check the server command specifier.
1504 co_unsigned32_t ac;
1505 switch (cs & CO_SDO_CS_MASK) {
1506 case CO_SDO_SCS_DN_SEG_RES: break;
1507 case CO_SDO_CS_ABORT:
1508 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1509 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1510 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1511 }
1512
1513 // Check the value of the toggle bit.
1514 if (__unlikely((cs & CO_SDO_SEG_TOGGLE) == sdo->toggle))
1516
1517 return co_csdo_dn_seg_state;
1518}
1519
1520static co_csdo_state_t *
1521co_csdo_up_ini_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1522{
1523 return co_csdo_abort_res(sdo, ac);
1524}
1525
1526static co_csdo_state_t *
1528{
1529 (void)tp;
1530
1532}
1533
1534static co_csdo_state_t *
1536{
1537 assert(sdo);
1538 assert(msg);
1539
1540 if (__unlikely(msg->len < 1))
1542 uint8_t cs = msg->data[0];
1543
1544 // Check the server command specifier.
1545 co_unsigned32_t ac;
1546 switch (cs & CO_SDO_CS_MASK) {
1547 case CO_SDO_SCS_UP_INI_RES: break;
1548 case CO_SDO_CS_ABORT:
1549 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1550 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1551 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1552 }
1553
1554 // Check the object index and sub-index.
1555 if (__unlikely(msg->len < 4))
1557 co_unsigned16_t idx = ldle_u16(msg->data + 1);
1558 co_unsigned8_t subidx = msg->data[3];
1559 if (__unlikely(idx != sdo->idx || subidx != sdo->subidx))
1561
1562 // Obtain the size from the command specifier.
1563 int exp = !!(cs & CO_SDO_INI_SIZE_EXP);
1564 sdo->size = 0;
1565 if (exp) {
1566 if (cs & CO_SDO_INI_SIZE_IND)
1567 sdo->size = CO_SDO_INI_SIZE_EXP_GET(cs);
1568 else
1569 sdo->size = msg->len - 4;
1570 } else if (cs & CO_SDO_INI_SIZE_IND) {
1571 if (__unlikely(msg->len < 8))
1573 sdo->size = ldle_u32(msg->data + 4);
1574 }
1575
1576 // Allocate the buffer.
1577 if (__unlikely(sdo->size && !membuf_reserve(&sdo->buf, sdo->size)))
1579
1580 if (exp) {
1581 // Perform an expedited transfer.
1582 memcpy(sdo->buf.cur, msg->data + 4, sdo->size);
1583 sdo->buf.cur += sdo->size;
1584
1585 return co_csdo_abort_ind(sdo, 0);
1586 } else {
1587 if (sdo->size && sdo->up_ind)
1588 sdo->up_ind(sdo, sdo->idx, sdo->subidx, sdo->size, 0,
1589 sdo->up_ind_data);
1590 if (sdo->timeout)
1591 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1593 return co_csdo_up_seg_state;
1594 }
1595}
1596
1597static co_csdo_state_t *
1598co_csdo_up_seg_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1599{
1600 return co_csdo_abort_res(sdo, ac);
1601}
1602
1603static co_csdo_state_t *
1605{
1606 (void)tp;
1607
1609}
1610
1611static co_csdo_state_t *
1613{
1614 assert(sdo);
1615 assert(msg);
1616
1617 if (__unlikely(msg->len < 1))
1619 uint8_t cs = msg->data[0];
1620
1621 // Check the server command specifier.
1622 co_unsigned32_t ac;
1623 switch (cs & CO_SDO_CS_MASK) {
1624 case CO_SDO_SCS_UP_SEG_RES: break;
1625 case CO_SDO_CS_ABORT:
1626 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1627 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1628 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1629 }
1630
1631 // Check the value of the toggle bit.
1632 if (__unlikely((cs & CO_SDO_SEG_TOGGLE) == sdo->toggle))
1633 return co_csdo_up_seg_state;
1634
1635 // Obtain the size of the segment.
1636 size_t n = CO_SDO_SEG_SIZE_GET(cs);
1637 if (__unlikely(msg->len < 1 + n))
1639 int last = !!(cs & CO_SDO_SEG_LAST);
1640
1641 // Reserve room in the buffer, if necessary.
1642 if (__unlikely(n && !membuf_reserve(&sdo->buf, n)))
1644
1645 // Copy the data to the buffer.
1646 memcpy(sdo->buf.cur, msg->data + 1, n);
1647 sdo->buf.cur += n;
1648
1649 if ((last || !(membuf_size(&sdo->buf) % (CO_SDO_MAX_SEQNO * 7)))
1650 && sdo->size && sdo->up_ind)
1651 sdo->up_ind(sdo, sdo->idx, sdo->subidx, sdo->size,
1652 membuf_size(&sdo->buf), sdo->up_ind_data);
1653 if (last) {
1654 // clang-format off
1655 if (__unlikely(sdo->size
1656 && membuf_size(&sdo->buf) != sdo->size))
1657 // clang-format on
1659 return co_csdo_abort_ind(sdo, 0);
1660 } else {
1661 if (sdo->timeout)
1662 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1664 return co_csdo_up_seg_state;
1665 }
1666}
1667
1668static co_csdo_state_t *
1670{
1671 return co_csdo_abort_res(sdo, ac);
1672}
1673
1674static co_csdo_state_t *
1676{
1677 (void)tp;
1678
1680}
1681
1682static co_csdo_state_t *
1684{
1685 assert(sdo);
1686 assert(msg);
1687
1688 if (__unlikely(msg->len < 1))
1690 uint8_t cs = msg->data[0];
1691
1692 // Check the server command specifier.
1693 co_unsigned32_t ac;
1694 switch (cs & CO_SDO_CS_MASK) {
1695 case CO_SDO_SCS_BLK_DN_RES: break;
1696 case CO_SDO_CS_ABORT:
1697 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1698 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1699 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1700 }
1701
1702 // Check the server subcommand.
1705
1706 // Check if the server supports generating a CRC.
1707 sdo->crc = !!(cs & CO_SDO_BLK_CRC);
1708
1709 // Check the object index and sub-index.
1710 if (__unlikely(msg->len < 4))
1712 co_unsigned16_t idx = ldle_u16(msg->data + 1);
1713 co_unsigned8_t subidx = msg->data[3];
1714 if (__unlikely(idx != sdo->idx || subidx != sdo->subidx))
1716
1717 // Load the number of segments per block.
1718 if (__unlikely(msg->len < 5))
1720 sdo->blksize = msg->data[4];
1721 if (__unlikely(!sdo->blksize || sdo->blksize > CO_SDO_MAX_SEQNO))
1723
1725}
1726
1727static co_csdo_state_t *
1729{
1730 assert(sdo);
1731
1732 size_t n = sdo->size - membuf_size(&sdo->buf);
1733 sdo->blksize = (uint8_t)MIN((n + 6) / 7, sdo->blksize);
1734
1735 if (sdo->size && sdo->dn_ind)
1736 sdo->dn_ind(sdo, sdo->idx, sdo->subidx, sdo->size,
1737 membuf_size(&sdo->buf), sdo->dn_ind_data);
1738 if (sdo->timeout)
1739 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1740 if (n) {
1741 // Send all segments in the current block.
1742 for (uint8_t seqno = 1; seqno <= sdo->blksize; seqno++)
1743 co_csdo_send_blk_dn_sub_req(sdo, seqno);
1744 return NULL;
1745 } else {
1748 }
1749}
1750
1751static co_csdo_state_t *
1753{
1754 return co_csdo_abort_res(sdo, ac);
1755}
1756
1757static co_csdo_state_t *
1759{
1760 (void)tp;
1761
1763}
1764
1765static co_csdo_state_t *
1767{
1768 assert(sdo);
1769 assert(msg);
1770
1771 if (__unlikely(msg->len < 1))
1773 uint8_t cs = msg->data[0];
1774
1775 // Check the server command specifier.
1776 co_unsigned32_t ac;
1777 switch (cs & CO_SDO_CS_MASK) {
1778 case CO_SDO_SCS_BLK_DN_RES: break;
1779 case CO_SDO_CS_ABORT:
1780 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1781 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1782 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1783 }
1784
1785 // Check the server subcommand.
1788
1789 if (__unlikely(msg->len < 3))
1791 uint8_t ackseq = msg->data[1];
1792 if (ackseq < sdo->blksize) {
1793 // If the sequence number of the last segment that was
1794 // successfully received is smaller than the number of segments
1795 // in the block, resend the missing segments.
1796 size_t n = (membuf_size(&sdo->buf) + 6) / 7;
1797 assert(n >= sdo->blksize);
1798 n -= sdo->blksize - ackseq;
1799 sdo->buf.cur = sdo->buf.begin + n * 7;
1800 }
1801
1802 // Read the number of segments in the next block.
1803 if (__unlikely(msg->len < 3))
1805 sdo->blksize = msg->data[2];
1806 if (__unlikely(!sdo->blksize || sdo->blksize > CO_SDO_MAX_SEQNO))
1808
1810}
1811
1812static co_csdo_state_t *
1814{
1815 return co_csdo_abort_res(sdo, ac);
1816}
1817
1818static co_csdo_state_t *
1820{
1821 (void)tp;
1822
1824}
1825
1826static co_csdo_state_t *
1828{
1829 assert(sdo);
1830 assert(msg);
1831
1832 if (__unlikely(msg->len < 1))
1834 uint8_t cs = msg->data[0];
1835
1836 // Check the server command specifier.
1837 co_unsigned32_t ac;
1838 switch (cs & CO_SDO_CS_MASK) {
1839 case CO_SDO_SCS_BLK_DN_RES: break;
1840 case CO_SDO_CS_ABORT:
1841 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1842 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1843 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1844 }
1845
1846 // Check the server subcommand.
1849
1850 return co_csdo_abort_ind(sdo, 0);
1851}
1852
1853static co_csdo_state_t *
1855{
1856 return co_csdo_abort_res(sdo, ac);
1857}
1858
1859static co_csdo_state_t *
1861{
1862 (void)tp;
1863
1865}
1866
1867static co_csdo_state_t *
1869{
1870 assert(sdo);
1871 assert(msg);
1872
1873 if (__unlikely(msg->len < 1))
1875 uint8_t cs = msg->data[0];
1876
1877 // Check the server command specifier.
1878 co_unsigned32_t ac;
1879 switch (cs & CO_SDO_CS_MASK) {
1881 // In case of a server-induced protocol switch, fall back to the
1882 // SDO upload protocol.
1883 return co_csdo_up_ini_on_recv(sdo, msg);
1884 case CO_SDO_SCS_BLK_UP_RES: break;
1885 case CO_SDO_CS_ABORT:
1886 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1887 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1888 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1889 }
1890
1891 // Check the server subcommand.
1892 if (__unlikely((cs & 0x01) != CO_SDO_SC_INI_BLK))
1894
1895 // Check if the server supports generating a CRC.
1896 sdo->crc = !!(cs & CO_SDO_BLK_CRC);
1897
1898 // Check the object index and sub-index.
1899 if (__unlikely(msg->len < 4))
1901 co_unsigned16_t idx = ldle_u16(msg->data + 1);
1902 co_unsigned8_t subidx = msg->data[3];
1903 if (__unlikely(idx != sdo->idx || subidx != sdo->subidx))
1905
1906 // Obtain the data set size.
1907 sdo->size = 0;
1908 if (cs & CO_SDO_BLK_SIZE_IND) {
1909 if (__unlikely(msg->len < 8))
1911 sdo->size = ldle_u32(msg->data + 4);
1912 }
1913
1914 // Allocate the buffer.
1915 if (__unlikely(sdo->size && !membuf_reserve(&sdo->buf, sdo->size)))
1917
1918 sdo->ackseq = 0;
1919
1920 if (sdo->timeout)
1921 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1924}
1925
1926static co_csdo_state_t *
1928{
1929 return co_csdo_abort_res(sdo, ac);
1930}
1931
1932static co_csdo_state_t *
1934{
1935 (void)tp;
1936
1938}
1939
1940static co_csdo_state_t *
1942{
1943 assert(sdo);
1944 assert(msg);
1945
1946 if (__unlikely(msg->len < 1))
1948 uint8_t cs = msg->data[0];
1949
1950 if (__unlikely(cs == CO_SDO_CS_ABORT)) {
1951 co_unsigned32_t ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1952 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1953 }
1954
1955 uint8_t seqno = cs & ~CO_SDO_SEQ_LAST;
1956 int last = !!(cs & CO_SDO_SEQ_LAST);
1957
1958 // Only accept sequential segments. Dropped segments will be resent
1959 // after the confirmation message.
1960 if (seqno == sdo->ackseq + 1) {
1961 sdo->ackseq++;
1962
1963 // Reserve room in the buffer, if necessary.
1964 if (__unlikely(!membuf_reserve(&sdo->buf, 7)))
1966
1967 // Copy the data to the buffer.
1968 memcpy(sdo->buf.cur, msg->data + 1, 7);
1969 sdo->buf.cur += 7;
1970 }
1971
1972 // If this is the last segment in the block, send a confirmation.
1973 if (seqno == sdo->blksize || last) {
1975 sdo->ackseq = 0;
1976 }
1977
1978 if (sdo->timeout)
1979 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1981}
1982
1983static co_csdo_state_t *
1985{
1986 return co_csdo_abort_res(sdo, ac);
1987}
1988
1989static co_csdo_state_t *
1991{
1992 (void)tp;
1993
1995}
1996
1997static co_csdo_state_t *
1999{
2000 assert(sdo);
2001 assert(msg);
2002
2003 if (__unlikely(msg->len < 1))
2005 uint8_t cs = msg->data[0];
2006
2007 // Check the server command specifier.
2008 co_unsigned32_t ac;
2009 switch (cs & CO_SDO_CS_MASK) {
2010 case CO_SDO_SCS_BLK_UP_RES: break;
2011 case CO_SDO_CS_ABORT:
2012 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
2013 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
2014 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
2015 }
2016
2017 // Check the server subcommand.
2020
2021 // Discard the bytes in the last segment that did not contain data.
2022 sdo->buf.cur -= 7 - CO_SDO_BLK_SIZE_GET(cs);
2023
2024 // Check the total length.
2025 if (__unlikely(sdo->size && membuf_size(&sdo->buf) != sdo->size))
2027
2028 // Check the CRC.
2029 if (sdo->crc) {
2030 uint16_t crc = ldle_u16(msg->data + 1);
2031 if (__unlikely(crc != co_crc(0, sdo->buf.begin, sdo->size)))
2033 }
2034
2036 return co_csdo_abort_ind(sdo, 0);
2037}
2038
2039static co_csdo_state_t *
2040co_csdo_abort_ind(co_csdo_t *sdo, co_unsigned32_t ac)
2041{
2042 assert(sdo);
2043
2044 sdo->ac = ac;
2045 return co_csdo_abort_state;
2046}
2047
2048static co_csdo_state_t *
2049co_csdo_abort_res(co_csdo_t *sdo, co_unsigned32_t ac)
2050{
2051 co_csdo_send_abort(sdo, ac);
2052 return co_csdo_abort_ind(sdo, ac);
2053}
2054
2055static int
2056co_csdo_dn_ind(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
2057 const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
2058{
2059 assert(sdo);
2060
2061 // Check whether the SDO exists and is valid.
2062 int valid_req = !(sdo->par.cobid_req & CO_SDO_COBID_VALID);
2063 int valid_res = !(sdo->par.cobid_res & CO_SDO_COBID_VALID);
2064 if (__unlikely(!valid_req || !valid_res)) {
2066 return -1;
2067 }
2068
2069 // Check whether we are in the waiting state.
2070 if (__unlikely(!co_csdo_is_idle(sdo))) {
2072 return -1;
2073 }
2074
2075 sdo->ac = 0;
2076 sdo->idx = idx;
2077 sdo->subidx = subidx;
2078 sdo->size = ptr ? n : 0;
2079
2080 sdo->toggle = 0;
2081 sdo->blksize = 0;
2082 sdo->ackseq = 0;
2083 sdo->crc = 0;
2084
2085 // Allocate the buffer.
2086 membuf_clear(&sdo->buf);
2087 if (__unlikely(sdo->size && !membuf_reserve(&sdo->buf, sdo->size)))
2088 return -1;
2089
2090 // Copy the bytes to the buffer.
2091 if (ptr)
2092 memcpy(sdo->buf.cur, ptr, sdo->size);
2093
2094 sdo->dn_con = con;
2095 sdo->dn_con_data = data;
2096
2097 sdo->up_con = NULL;
2098 sdo->up_con_data = NULL;
2099
2100 return 0;
2101}
2102
2103static int
2104co_csdo_up_ind(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
2105 co_csdo_up_con_t *con, void *data)
2106{
2107 assert(sdo);
2108
2109 // Check whether the SDO exists and is valid.
2110 int valid_req = !(sdo->par.cobid_req & CO_SDO_COBID_VALID);
2111 int valid_res = !(sdo->par.cobid_res & CO_SDO_COBID_VALID);
2112 if (__unlikely(!valid_req || !valid_res)) {
2114 return -1;
2115 }
2116
2117 // Check whether we are in the waiting state.
2118 if (__unlikely(!co_csdo_is_idle(sdo))) {
2120 return -1;
2121 }
2122
2123 sdo->ac = 0;
2124 sdo->idx = idx;
2125 sdo->subidx = subidx;
2126 sdo->size = 0;
2127
2128 sdo->toggle = 0;
2129 sdo->blksize = 0;
2130 sdo->ackseq = 0;
2131 sdo->crc = 0;
2132
2133 membuf_clear(&sdo->buf);
2134
2135 sdo->dn_con = NULL;
2136 sdo->dn_con_data = NULL;
2137
2138 sdo->up_con = con;
2139 sdo->up_con_data = data;
2140
2141 return 0;
2142}
2143
2144static void
2145co_csdo_send_abort(co_csdo_t *sdo, co_unsigned32_t ac)
2146{
2147 assert(sdo);
2148
2149 struct can_msg msg;
2151 stle_u32(msg.data + 4, ac);
2152 can_net_send(sdo->net, &msg);
2153}
2154
2155static void
2157{
2158 assert(sdo);
2159 assert(sdo->size && sdo->size <= 4);
2160
2162
2163 struct can_msg msg;
2164 co_csdo_init_ini_req(sdo, &msg, cs);
2165 memcpy(msg.data + 4, sdo->buf.cur, sdo->size);
2166 sdo->buf.cur += sdo->size;
2167 can_net_send(sdo->net, &msg);
2168}
2169
2170static void
2172{
2173 assert(sdo);
2174 assert(!sdo->size || sdo->size > 4);
2175
2177
2178 struct can_msg msg;
2179 co_csdo_init_ini_req(sdo, &msg, cs);
2180 stle_u32(msg.data + 4, sdo->size);
2181 can_net_send(sdo->net, &msg);
2182
2183 if (sdo->size && sdo->dn_ind)
2184 sdo->dn_ind(sdo, sdo->idx, sdo->subidx, sdo->size, 0,
2185 sdo->dn_ind_data);
2186}
2187
2188static void
2189co_csdo_send_dn_seg_req(co_csdo_t *sdo, uint32_t n, int last)
2190{
2191 assert(sdo);
2192 assert(n <= 7);
2193
2194 uint8_t cs = CO_SDO_CCS_DN_SEG_REQ | sdo->toggle
2196 sdo->toggle ^= CO_SDO_SEG_TOGGLE;
2197 if (last)
2198 cs |= CO_SDO_SEG_LAST;
2199
2200 struct can_msg msg;
2201 co_csdo_init_seg_req(sdo, &msg, cs);
2202 memcpy(msg.data + 1, sdo->buf.cur, n);
2203 sdo->buf.cur += n;
2204 can_net_send(sdo->net, &msg);
2205
2206 if ((last || !(membuf_size(&sdo->buf) % (CO_SDO_MAX_SEQNO * 7)))
2207 && sdo->size && sdo->dn_ind)
2208 sdo->dn_ind(sdo, sdo->idx, sdo->subidx, sdo->size,
2209 membuf_size(&sdo->buf), sdo->dn_ind_data);
2210}
2211
2212static void
2214{
2215 assert(sdo);
2216
2217 uint8_t cs = CO_SDO_CCS_UP_INI_REQ;
2218
2219 struct can_msg msg;
2220 co_csdo_init_ini_req(sdo, &msg, cs);
2221 can_net_send(sdo->net, &msg);
2222}
2223
2224static void
2226{
2227 assert(sdo);
2228
2229 uint8_t cs = CO_SDO_CCS_UP_SEG_REQ | sdo->toggle;
2230 sdo->toggle ^= CO_SDO_SEG_TOGGLE;
2231
2232 struct can_msg msg;
2233 co_csdo_init_seg_req(sdo, &msg, cs);
2234 can_net_send(sdo->net, &msg);
2235}
2236
2237static void
2239{
2240 assert(sdo);
2241
2244
2245 struct can_msg msg;
2246 co_csdo_init_ini_req(sdo, &msg, cs);
2247 stle_u32(msg.data + 4, sdo->size);
2248 can_net_send(sdo->net, &msg);
2249}
2250
2251static void
2253{
2254 assert(sdo);
2255 assert(seqno && seqno <= CO_SDO_MAX_SEQNO);
2256
2257 size_t n = sdo->size - membuf_size(&sdo->buf);
2258 int last = n <= 7;
2259 n = MIN(n, 7);
2260
2261 uint8_t cs = seqno;
2262 if (last)
2263 cs |= CO_SDO_SEQ_LAST;
2264
2265 struct can_msg msg;
2266 co_csdo_init_seg_req(sdo, &msg, cs);
2267 memcpy(msg.data + 1, sdo->buf.cur, n);
2268 sdo->buf.cur += n;
2269 can_net_send(sdo->net, &msg);
2270}
2271
2272static void
2274{
2275 assert(sdo);
2276
2277 // Compute the number of bytes in the last segment containing data.
2278 uint8_t n = sdo->size ? (sdo->size - 1) % 7 + 1 : 0;
2279
2282
2283 uint16_t crc = sdo->crc ? co_crc(0, sdo->buf.begin, sdo->size) : 0;
2284
2285 struct can_msg msg;
2286 co_csdo_init_seg_req(sdo, &msg, cs);
2287 stle_u16(msg.data + 1, crc);
2288 can_net_send(sdo->net, &msg);
2289}
2290
2291static void
2293{
2294 assert(sdo);
2295
2297
2298 struct can_msg msg;
2299 co_csdo_init_ini_req(sdo, &msg, cs);
2300 msg.data[4] = sdo->blksize;
2301 msg.data[5] = pst;
2302 can_net_send(sdo->net, &msg);
2303}
2304
2305static void
2307{
2308 assert(sdo);
2309
2311
2312 struct can_msg msg;
2313 co_csdo_init_seg_req(sdo, &msg, cs);
2314 can_net_send(sdo->net, &msg);
2315
2316 if (sdo->size && sdo->up_ind)
2317 sdo->up_ind(sdo, sdo->idx, sdo->subidx, sdo->size, 0,
2318 sdo->up_ind_data);
2319}
2320
2321static void
2323{
2324 assert(sdo);
2325
2327
2328 struct can_msg msg;
2329 co_csdo_init_seg_req(sdo, &msg, cs);
2330 msg.data[1] = sdo->ackseq;
2331 msg.data[2] = sdo->blksize;
2332 can_net_send(sdo->net, &msg);
2333
2334 if (sdo->size && sdo->up_ind)
2335 sdo->up_ind(sdo, sdo->idx, sdo->subidx, sdo->size,
2336 membuf_size(&sdo->buf), sdo->up_ind_data);
2337}
2338
2339static void
2341{
2342 assert(sdo);
2343
2345
2346 struct can_msg msg;
2347 co_csdo_init_seg_req(sdo, &msg, cs);
2348 can_net_send(sdo->net, &msg);
2349}
2350
2351static void
2352co_csdo_init_ini_req(co_csdo_t *sdo, struct can_msg *msg, uint8_t cs)
2353{
2354 assert(sdo);
2355 assert(msg);
2356
2357 *msg = (struct can_msg)CAN_MSG_INIT;
2358 msg->id = sdo->par.cobid_req;
2359 if (sdo->par.cobid_req & CO_SDO_COBID_FRAME) {
2360 msg->id &= CAN_MASK_EID;
2361 msg->flags |= CAN_FLAG_IDE;
2362 } else {
2363 msg->id &= CAN_MASK_BID;
2364 }
2365 msg->len = CAN_MAX_LEN;
2366 msg->data[0] = cs;
2367 stle_u16(msg->data + 1, sdo->idx);
2368 msg->data[3] = sdo->subidx;
2369}
2370
2371static void
2372co_csdo_init_seg_req(co_csdo_t *sdo, struct can_msg *msg, uint8_t cs)
2373{
2374 assert(sdo);
2375 assert(msg);
2376
2377 *msg = (struct can_msg)CAN_MSG_INIT;
2378 msg->id = sdo->par.cobid_req;
2379 if (sdo->par.cobid_req & CO_SDO_COBID_FRAME) {
2380 msg->id &= CAN_MASK_EID;
2381 msg->flags |= CAN_FLAG_IDE;
2382 } else {
2383 msg->id &= CAN_MASK_BID;
2384 }
2385 msg->len = CAN_MAX_LEN;
2386 msg->data[0] = cs;
2387}
2388
2389#endif // !LELY_NO_CO_CSDO
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
static co_unsigned32_t co_1280_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen objects 1280..12FF (SDO client para...
Definition: csdo.c:1170
static int co_csdo_recv(const struct can_msg *msg, void *data)
The CAN receive callback function for a Client-SDO service.
Definition: csdo.c:1272
static void co_csdo_emit_recv(co_csdo_t *sdo, const struct can_msg *msg)
Invokes the 'CAN frame received' transition function of the current state of a Client-SDO service.
Definition: csdo.c:1343
static void co_csdo_send_dn_ini_req(co_csdo_t *sdo)
Sends a Client-SDO 'download initiate' request.
Definition: csdo.c:2171
int co_csdo_up_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_csdo_up_con_t *con, void *data)
Submits an upload request to a remote Server-SDO.
Definition: csdo.c:1080
static void co_csdo_send_up_ini_req(co_csdo_t *sdo)
Sends a Client-SDO 'upload initiate' request.
Definition: csdo.c:2213
int co_dev_up_req(const co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx, co_csdo_up_con_t *con, void *data)
Submits an upload request to a local device.
Definition: csdo.c:675
static co_csdo_state_t * co_csdo_up_seg_on_recv(co_csdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'upload segment' state.
Definition: csdo.c:1612
static co_csdo_state_t * co_csdo_blk_up_end_on_recv(co_csdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'block upload end' state.
Definition: csdo.c:1998
static int co_csdo_timer(const struct timespec *tp, void *data)
The CAN timer callback function for a Client-SDO service.
Definition: csdo.c:1294
static co_csdo_state_t * co_csdo_blk_up_ini_on_recv(co_csdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'block upload initiate' state.
Definition: csdo.c:1868
static co_csdo_state_t * co_csdo_dn_seg_on_recv(co_csdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'download segment' state.
Definition: csdo.c:1494
int co_csdo_is_idle(const co_csdo_t *sdo)
Returns 1 if the specified Client-SDO service is idle, and 0 if a transfer is ongoing.
Definition: csdo.c:995
static co_csdo_state_t *const co_csdo_blk_up_end_state
The 'block upload end' state.
Definition: csdo.c:469
static co_csdo_state_t * co_csdo_up_seg_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'upload segment' state.
Definition: csdo.c:1598
static co_csdo_state_t * co_csdo_blk_up_end_on_time(co_csdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'block upload end' state.
Definition: csdo.c:1990
int co_csdo_blk_up_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, uint8_t pst, co_csdo_up_con_t *con, void *data)
Submits a block upload request to a remote Server-SDO.
Definition: csdo.c:1121
static co_csdo_state_t * co_csdo_up_seg_on_time(co_csdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'upload segment' state.
Definition: csdo.c:1604
static co_csdo_state_t *const co_csdo_blk_dn_end_state
The 'block download end' state.
Definition: csdo.c:398
static void co_csdo_send_blk_dn_sub_req(co_csdo_t *sdo, uint8_t seqno)
Sends a Client-SDO 'block download sub-block' request.
Definition: csdo.c:2252
static co_csdo_state_t * co_csdo_blk_dn_end_on_time(co_csdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'block download end' state.
Definition: csdo.c:1819
static void co_csdo_send_up_seg_req(co_csdo_t *sdo)
Sends a Client-SDO 'upload segment' request.
Definition: csdo.c:2225
int co_csdo_dn_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
Submits a download request to a remote Server-SDO.
Definition: csdo.c:1011
int co_dev_dn_val_req(co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned16_t type, const void *val, co_csdo_dn_con_t *con, void *data)
Submits a download request to a local device.
Definition: csdo.c:637
static co_csdo_state_t * co_csdo_abort_ind(co_csdo_t *sdo, co_unsigned32_t ac)
Processes an abort transfer indication by aborting any ongoing transfer of a Client-SDO and returning...
Definition: csdo.c:2040
static co_csdo_state_t *const co_csdo_blk_up_ini_state
The 'block upload initiate' state.
Definition: csdo.c:422
static void co_csdo_init_seg_req(co_csdo_t *sdo, struct can_msg *msg, uint8_t cs)
Initializes a Client-SDO download/upload segment request CAN frame.
Definition: csdo.c:2372
static int co_csdo_update(co_csdo_t *sdo)
Updates and (de)activates a Client-SDO service.
Definition: csdo.c:1143
int co_dev_dn_req(co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx, const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
Submits a download request to a local device.
Definition: csdo.c:600
static co_csdo_state_t * co_csdo_wait_on_recv(co_csdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'waiting' state.
Definition: csdo.c:1362
static co_csdo_state_t * co_csdo_dn_ini_on_time(co_csdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'download initiate' state.
Definition: csdo.c:1422
static co_csdo_state_t * co_csdo_blk_dn_ini_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'block download initiate' state.
Definition: csdo.c:1669
static co_csdo_state_t * co_csdo_blk_up_sub_on_recv(co_csdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'block upload sub-block' state.
Definition: csdo.c:1941
static co_csdo_state_t * co_csdo_blk_up_sub_on_time(co_csdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'block upload sub-block' state.
Definition: csdo.c:1933
can_net_t * co_csdo_get_net(const co_csdo_t *sdo)
Returns a pointer to the CAN network of a Client-SDO.
Definition: csdo.c:904
static void co_csdo_enter(co_csdo_t *sdo, co_csdo_state_t *next)
Enters the specified state of a Client-SDO service and invokes the exit and entry functions.
Definition: csdo.c:1306
co_dev_t * co_csdo_get_dev(const co_csdo_t *sdo)
Returns a pointer to the CANopen device of a Client-SDO.
Definition: csdo.c:912
static int co_csdo_up_ind(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_csdo_up_con_t *con, void *data)
Processes an upload request from a Client-SDO by checking and updating the state.
Definition: csdo.c:2104
static void co_csdo_send_blk_up_sub_res(co_csdo_t *sdo)
Sends a Client-SDO 'block upload sub-block' response.
Definition: csdo.c:2322
void co_csdo_set_timeout(co_csdo_t *sdo, int timeout)
Sets the timeout of a Client-SDO.
Definition: csdo.c:944
static co_csdo_state_t * co_csdo_abort_res(co_csdo_t *sdo, co_unsigned32_t ac)
Sends an abort transfer request and aborts any ongoing transfer by invoking co_csdo_abort_ind().
Definition: csdo.c:2049
static void co_csdo_send_blk_up_ini_req(co_csdo_t *sdo, uint8_t pst)
Sends a Client-SDO 'block upload initiate' request.
Definition: csdo.c:2292
int co_csdo_get_timeout(const co_csdo_t *sdo)
Returns the timeout (in milliseconds) of a Client-SDO.
Definition: csdo.c:936
void co_csdo_destroy(co_csdo_t *csdo)
Destroys a CANopen Client-SDO service.
Definition: csdo.c:894
static void co_csdo_send_blk_up_end_res(co_csdo_t *sdo)
Sends a Client-SDO 'block upload end' response.
Definition: csdo.c:2340
static co_csdo_state_t *const co_csdo_dn_seg_state
The 'download segment' state.
Definition: csdo.c:280
static co_csdo_state_t *const co_csdo_abort_state
The 'abort transfer' state.
Definition: csdo.c:229
int co_csdo_blk_dn_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
Submits a block download request to a remote Server-SDO.
Definition: csdo.c:1099
void co_csdo_set_up_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO upload reques...
Definition: csdo.c:986
static co_csdo_state_t * co_csdo_blk_up_sub_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'block upload sub-block' state.
Definition: csdo.c:1927
static void co_csdo_emit_time(co_csdo_t *sdo, const struct timespec *tp)
Invokes the 'timeout' transition function of the current state of a Client-SDO service.
Definition: csdo.c:1333
static co_csdo_state_t *const co_csdo_up_ini_state
The 'upload initiate' state.
Definition: csdo.c:301
static co_csdo_state_t * co_csdo_abort_on_enter(co_csdo_t *sdo)
The entry function of the 'abort transfer' state.
Definition: csdo.c:1381
static co_csdo_state_t * co_csdo_dn_ini_on_recv(co_csdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'download initiate' state.
Definition: csdo.c:1430
void co_csdo_abort_req(co_csdo_t *sdo, co_unsigned32_t ac)
Submits an abort transfer request to a remote Server-SDO.
Definition: csdo.c:1003
static void co_csdo_send_dn_seg_req(co_csdo_t *sdo, uint32_t n, int last)
Sends a Client-SDO 'download segment' request.
Definition: csdo.c:2189
static co_csdo_state_t * co_csdo_dn_ini_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'download initiate' state.
Definition: csdo.c:1416
static co_csdo_state_t * co_csdo_dn_seg_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'download segment' state.
Definition: csdo.c:1480
static co_csdo_state_t * co_csdo_blk_dn_end_on_recv(co_csdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'block download end' state.
Definition: csdo.c:1827
static co_csdo_state_t *const co_csdo_wait_state
The 'waiting' state.
Definition: csdo.c:215
void co_csdo_get_up_ind(const co_csdo_t *sdo, co_csdo_ind_t **pind, void **pdata)
Retrieves the indication function used to notify the user of the progress of the current SDO upload r...
Definition: csdo.c:975
static void co_csdo_send_blk_dn_end_req(co_csdo_t *sdo)
Sends a Client-SDO 'block download end' request.
Definition: csdo.c:2273
static co_csdo_state_t * co_csdo_dn_seg_on_enter(co_csdo_t *sdo)
The entry function of the 'download segment' state.
Definition: csdo.c:1461
const struct co_sdo_par * co_csdo_get_par(const co_csdo_t *sdo)
Returns a pointer to the SDO parameter record of a Client-SDO.
Definition: csdo.c:928
static co_csdo_state_t *const co_csdo_blk_dn_ini_state
The 'block download initiate' state.
Definition: csdo.c:346
static co_csdo_state_t * co_csdo_blk_dn_ini_on_time(co_csdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'block download initiate' state.
Definition: csdo.c:1675
static void co_csdo_emit_abort(co_csdo_t *sdo, co_unsigned32_t ac)
Invokes the 'abort' transition function of the current state of a Client-SDO service.
Definition: csdo.c:1323
static co_csdo_state_t *const co_csdo_blk_up_sub_state
The 'block upload sub-block' state.
Definition: csdo.c:446
static co_csdo_state_t * co_csdo_blk_up_ini_on_time(co_csdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'block upload initiate' state.
Definition: csdo.c:1860
static co_csdo_state_t * co_csdo_blk_up_end_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'block upload end' state.
Definition: csdo.c:1984
static void co_csdo_send_start_up_req(co_csdo_t *sdo)
Sends a Client-SDO 'start upload' request.
Definition: csdo.c:2306
static co_csdo_state_t * co_csdo_wait_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'waiting' state.
Definition: csdo.c:1353
static co_csdo_state_t * co_csdo_blk_dn_sub_on_time(co_csdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'block download sub-block' state.
Definition: csdo.c:1758
static co_csdo_state_t * co_csdo_up_ini_on_recv(co_csdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'upload initiate' state.
Definition: csdo.c:1535
void co_csdo_set_dn_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO download requ...
Definition: csdo.c:966
static int co_csdo_dn_ind(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
Processes a download request from a Client-SDO by checking and updating the state and copying the val...
Definition: csdo.c:2056
static void co_csdo_send_blk_dn_ini_req(co_csdo_t *sdo)
Sends a Client-SDO 'block download initiate' request.
Definition: csdo.c:2238
co_csdo_t * co_csdo_create(can_net_t *net, co_dev_t *dev, co_unsigned8_t num)
Creates a new CANopen Client-SDO service.
Definition: csdo.c:867
static co_csdo_state_t * co_csdo_up_ini_on_time(co_csdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'upload initiate' state.
Definition: csdo.c:1527
static co_csdo_state_t *const co_csdo_blk_dn_sub_state
The 'block download sub-block' state.
Definition: csdo.c:374
co_unsigned8_t co_csdo_get_num(const co_csdo_t *sdo)
Returns the SDO number of a Client-SDO.
Definition: csdo.c:920
static co_csdo_state_t * co_csdo_blk_dn_sub_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'block download sub-block' state.
Definition: csdo.c:1752
static co_csdo_state_t *const co_csdo_dn_ini_state
The 'download initiate' state.
Definition: csdo.c:253
void co_csdo_get_dn_ind(const co_csdo_t *sdo, co_csdo_ind_t **pind, void **pdata)
Retrieves the indication function used to notify the user of the progress of the current SDO download...
Definition: csdo.c:955
static void co_csdo_send_dn_exp_req(co_csdo_t *sdo)
Sends a Client-SDO 'download initiate' (expedited) request.
Definition: csdo.c:2156
int co_csdo_dn_val_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned16_t type, const void *val, co_csdo_dn_con_t *con, void *data)
Submits a download request to a remote Server-SDO.
Definition: csdo.c:1036
static void co_csdo_abort_on_leave(co_csdo_t *sdo)
The exit function of the 'abort transfer' state.
Definition: csdo.c:1391
static void co_csdo_send_abort(co_csdo_t *sdo, co_unsigned32_t ac)
Sends an abort transfer request.
Definition: csdo.c:2145
static co_csdo_state_t * co_csdo_blk_up_ini_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'block upload initiate' state.
Definition: csdo.c:1854
static co_csdo_state_t * co_csdo_blk_dn_sub_on_recv(co_csdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'block download sub-block' state.
Definition: csdo.c:1766
static co_csdo_state_t *const co_csdo_up_seg_state
The 'upload segment' state.
Definition: csdo.c:322
static co_csdo_state_t * co_csdo_up_ini_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'upload initiate' state.
Definition: csdo.c:1521
static co_csdo_state_t * co_csdo_dn_seg_on_time(co_csdo_t *sdo, const struct timespec *tp)
The 'timeout' transition function of the 'download segment' state.
Definition: csdo.c:1486
static co_csdo_state_t * co_csdo_blk_dn_sub_on_enter(co_csdo_t *sdo)
The entry function of the 'block download sub-block' state.
Definition: csdo.c:1728
static co_csdo_state_t * co_csdo_blk_dn_ini_on_recv(co_csdo_t *sdo, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'block download initiate' state.
Definition: csdo.c:1683
static void co_csdo_init_ini_req(co_csdo_t *sdo, struct can_msg *msg, uint8_t cs)
Initializes a Client-SDO download/upload initiate request CAN frame.
Definition: csdo.c:2352
static co_csdo_state_t * co_csdo_blk_dn_end_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'block download end' state.
Definition: csdo.c:1813
This header file is part of the CANopen library; it contains the Client-SDO declarations.
void co_csdo_up_con_t(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac, const void *ptr, size_t n, void *data)
The type of a CANopen Client-SDO upload confirmation callback function, invoked when an upload reques...
Definition: csdo.h:59
void co_csdo_dn_con_t(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac, void *data)
The type of a CANopen Client-SDO download confirmation callback function, invoked when a download req...
Definition: csdo.h:43
void co_csdo_ind_t(const co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
The type of a CANopen Client-SDO request progress indication function, used to notify the user of the...
Definition: csdo.h:79
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
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition: dev.h:56
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
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
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_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_REQ_INIT
The static initializer for struct co_sdo_req.
Definition: sdo.h:203
int co_sdo_req_up_val(struct co_sdo_req *req, co_unsigned16_t type, const void *val, co_unsigned32_t *pac)
Writes the specified value to a buffer and constructs a CANopen SDO upload request.
Definition: sdo.c:278
int co_sdo_req_up(struct co_sdo_req *req, const void *ptr, size_t n, co_unsigned32_t *pac)
Writes the specified bytes to a buffer and constructs a CANopen SDO upload request.
Definition: sdo.c:251
#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_ERROR
SDO abort code: General error.
Definition: sdo.h:150
#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
#define CO_SDO_AC_NO_DATA
SDO abort code: No data available.
Definition: sdo.h:175
#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
#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
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
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
#define MEMBUF_INIT
The static initializer for struct membuf.
Definition: membuf.h:45
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
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 Client-SDO state.
Definition: csdo.c:163
co_csdo_state_t *(* on_enter)(co_csdo_t *sdo)
A pointer to the function invoked when a new state is entered.
Definition: csdo.c:165
co_csdo_state_t *(* on_recv)(co_csdo_t *sdo, const struct can_msg *msg)
A pointer to the transition function invoked when a CAN frame has been received.
Definition: csdo.c:194
void(* on_leave)(co_csdo_t *sdo)
A pointer to the function invoked when the current state is left.
Definition: csdo.c:196
co_csdo_state_t *(* on_time)(co_csdo_t *sdo, const struct timespec *tp)
A pointer to the transition function invoked when a timeout occurs.
Definition: csdo.c:184
co_csdo_state_t *(* on_abort)(co_csdo_t *sdo, co_unsigned32_t ac)
A pointer to the transition function invoked when an abort code has been received.
Definition: csdo.c:175
A CANopen Client-SDO.
Definition: csdo.c:45
void * up_ind_data
A pointer to user-specified data for up_ind.
Definition: csdo.c:95
void * dn_con_data
A pointer to user-specified data for dn_con.
Definition: csdo.c:83
uint8_t ackseq
The sequence number of the last successfully received segment.
Definition: csdo.c:75
can_timer_t * timer
A pointer to the CAN timer.
Definition: csdo.c:59
co_csdo_ind_t * up_ind
A pointer to the upload progress indication function.
Definition: csdo.c:93
void * up_con_data
A pointer to user-specified data for up_con.
Definition: csdo.c:91
co_unsigned8_t subidx
The current object sub-index.
Definition: csdo.c:67
int timeout
The SDO timeout (in milliseconds).
Definition: csdo.c:57
co_unsigned16_t idx
The current object index.
Definition: csdo.c:65
co_unsigned8_t num
The SDO number.
Definition: csdo.c:51
co_csdo_up_con_t * up_con
A pointer to the upload confirmation function.
Definition: csdo.c:89
void * dn_ind_data
A pointer to user-specified data for dn_ind.
Definition: csdo.c:87
co_csdo_ind_t * dn_ind
A pointer to the download progress indication function.
Definition: csdo.c:85
co_csdo_dn_con_t * dn_con
A pointer to the download confirmation function.
Definition: csdo.c:81
co_unsigned32_t ac
The current abort code.
Definition: csdo.c:63
uint8_t blksize
The number of segments per block.
Definition: csdo.c:73
struct membuf buf
The buffer.
Definition: csdo.c:79
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: csdo.c:55
uint32_t size
The data set size (in bytes).
Definition: csdo.c:69
co_csdo_state_t * state
A pointer to the current state.
Definition: csdo.c:61
struct co_sdo_par par
The SDO parameter record.
Definition: csdo.c:53
can_net_t * net
A pointer to a CAN network interface.
Definition: csdo.c:47
uint8_t toggle
The current value of the toggle bit.
Definition: csdo.c:71
co_dev_t * dev
A pointer to a CANopen device.
Definition: csdo.c:49
unsigned crc
A flag indicating whether a CRC should be generated.
Definition: csdo.c:77
A CANopen device.
Definition: dev.c:38
A CANopen object.
Definition: obj.h:32
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 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
char * begin
A pointer to the first byte in the buffer.
Definition: membuf.h:39
char * cur
A pointer to one past the last byte written to the buffer.
Definition: membuf.h:37
A time type with nanosecond resolution.
Definition: time.h:83
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:163
This header file is part of the CANopen library; it contains the CANopen value declarations.
size_t co_val_write(co_unsigned16_t type, const void *val, uint8_t *begin, uint8_t *end)
Writes a value of the specified data type to a memory buffer.
Definition: val.c:718
size_t co_val_sizeof(co_unsigned16_t type, const void *val)
Returns the size (in bytes) of a value of the specified data type.
Definition: val.c:293
void co_val_fini(co_unsigned16_t type, void *val)
Finalizes a value of the specified data type.
Definition: val.c:273