Lely core libraries 2.3.5
csdo.c
Go to the documentation of this file.
1
23
24#include "co.h"
25
26#if !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#include <string.h>
40
41#if LELY_NO_MALLOC
42#ifndef CO_CSDO_MEMBUF_SIZE
48#define CO_CSDO_MEMBUF_SIZE 8
49#endif
50#endif
51
52struct __co_csdo_state;
54typedef const struct __co_csdo_state co_csdo_state_t;
55
59 co_unsigned32_t n;
61 const uint_least8_t *begin;
63 const uint_least8_t *end;
67 void *data;
68};
69
71struct __co_csdo {
77 co_unsigned8_t num;
89 co_unsigned32_t ac;
91 co_unsigned16_t idx;
93 co_unsigned8_t subidx;
95 co_unsigned32_t size;
97 co_unsigned8_t toggle;
99 co_unsigned8_t blksize;
101 co_unsigned8_t pst;
103 co_unsigned8_t ackseq;
105 unsigned crc : 1;
109 struct membuf *up_buf;
114 struct membuf buf;
115#if LELY_NO_MALLOC
120 char begin[CO_CSDO_MEMBUF_SIZE];
121#endif
140};
141
148static int co_csdo_update(co_csdo_t *sdo);
149
156static co_unsigned32_t co_1280_dn_ind(
157 co_sub_t *sub, struct co_sdo_req *req, void *data);
158
164static int co_csdo_recv(const struct can_msg *msg, void *data);
165
171static int co_csdo_timer(const struct timespec *tp, void *data);
172
177static inline void co_csdo_enter(co_csdo_t *sdo, co_csdo_state_t *next);
178
186static inline void co_csdo_emit_abort(co_csdo_t *sdo, co_unsigned32_t ac);
187
195static inline void co_csdo_emit_time(co_csdo_t *sdo, const struct timespec *tp);
196
204static inline void co_csdo_emit_recv(co_csdo_t *sdo, const struct can_msg *msg);
205
209 co_csdo_state_t *(*on_enter)(co_csdo_t *sdo);
219 co_csdo_state_t *(*on_abort)(co_csdo_t *sdo, co_unsigned32_t ac);
228 co_csdo_state_t *(*on_time)(co_csdo_t *sdo, const struct timespec *tp);
238 co_csdo_state_t *(*on_recv)(co_csdo_t *sdo, const struct can_msg *msg);
240 void (*on_leave)(co_csdo_t *sdo);
241};
242
243#define LELY_CO_DEFINE_STATE(name, ...) \
244 static co_csdo_state_t *const name = &(co_csdo_state_t){ __VA_ARGS__ };
245
248 co_csdo_t *sdo, co_unsigned32_t ac);
249
251// clang-format off
252LELY_CO_DEFINE_STATE(co_csdo_stopped_state,
253 .on_abort = &co_csdo_stopped_on_abort
255// clang-format on
256
257
259 co_csdo_t *sdo, co_unsigned32_t ac);
260
263 co_csdo_t *sdo, const struct can_msg *msg);
264
266// clang-format off
267LELY_CO_DEFINE_STATE(co_csdo_wait_state,
268 .on_abort = &co_csdo_wait_on_abort,
269 .on_recv = &co_csdo_wait_on_recv
271// clang-format on
272
275
277static void co_csdo_abort_on_leave(co_csdo_t *sdo);
278
280// clang-format off
281LELY_CO_DEFINE_STATE(co_csdo_abort_state,
282 .on_enter = &co_csdo_abort_on_enter,
283 .on_leave = &co_csdo_abort_on_leave
285// clang-format on
286
289 co_csdo_t *sdo, co_unsigned32_t ac);
290
293 co_csdo_t *sdo, const struct timespec *tp);
294
300 co_csdo_t *sdo, const struct can_msg *msg);
301
303// clang-format off
304LELY_CO_DEFINE_STATE(co_csdo_dn_ini_state,
305 .on_abort = &co_csdo_dn_ini_on_abort,
306 .on_time = &co_csdo_dn_ini_on_time,
307 .on_recv = &co_csdo_dn_ini_on_recv
309// clang-format on
310
313
316 co_csdo_t *sdo, co_unsigned32_t ac);
317
320 co_csdo_t *sdo, const struct timespec *tp);
321
326 co_csdo_t *sdo, const struct can_msg *msg);
327
329// clang-format off
330LELY_CO_DEFINE_STATE(co_csdo_dn_seg_state,
331 .on_enter = &co_csdo_dn_seg_on_enter,
332 .on_abort = &co_csdo_dn_seg_on_abort,
333 .on_time = &co_csdo_dn_seg_on_time,
334 .on_recv = &co_csdo_dn_seg_on_recv
336// clang-format on
337
340 co_csdo_t *sdo, co_unsigned32_t ac);
341
344 co_csdo_t *sdo, const struct timespec *tp);
345
348 co_csdo_t *sdo, const struct can_msg *msg);
349
351// clang-format off
352LELY_CO_DEFINE_STATE(co_csdo_up_ini_state,
353 .on_abort = &co_csdo_up_ini_on_abort,
354 .on_time = &co_csdo_up_ini_on_time,
355 .on_recv = &co_csdo_up_ini_on_recv
357// clang-format on
358
361 co_csdo_t *sdo, co_unsigned32_t ac);
362
365 co_csdo_t *sdo, const struct timespec *tp);
366
369 co_csdo_t *sdo, const struct can_msg *msg);
370
372// clang-format off
373LELY_CO_DEFINE_STATE(co_csdo_up_seg_state,
374 .on_abort = &co_csdo_up_seg_on_abort,
375 .on_time = &co_csdo_up_seg_on_time,
376 .on_recv = &co_csdo_up_seg_on_recv
378// clang-format on
379
382 co_csdo_t *sdo, co_unsigned32_t ac);
383
386 co_csdo_t *sdo, const struct timespec *tp);
387
393 co_csdo_t *sdo, const struct can_msg *msg);
394
396// clang-format off
397LELY_CO_DEFINE_STATE(co_csdo_blk_dn_ini_state,
398 .on_abort = &co_csdo_blk_dn_ini_on_abort,
399 .on_time = &co_csdo_blk_dn_ini_on_time,
402// clang-format on
403
406
409 co_csdo_t *sdo, co_unsigned32_t ac);
410
413 co_csdo_t *sdo, const struct timespec *tp);
414
420 co_csdo_t *sdo, const struct can_msg *msg);
421
423// clang-format off
424LELY_CO_DEFINE_STATE(co_csdo_blk_dn_sub_state,
425 .on_enter = &co_csdo_blk_dn_sub_on_enter,
426 .on_abort = &co_csdo_blk_dn_sub_on_abort,
427 .on_time = &co_csdo_blk_dn_sub_on_time,
430// clang-format on
431
434 co_csdo_t *sdo, co_unsigned32_t ac);
435
438 co_csdo_t *sdo, const struct timespec *tp);
439
445 co_csdo_t *sdo, const struct can_msg *msg);
446
448// clang-format off
449LELY_CO_DEFINE_STATE(co_csdo_blk_dn_end_state,
450 .on_abort = &co_csdo_blk_dn_end_on_abort,
451 .on_time = &co_csdo_blk_dn_end_on_time,
454// clang-format on
455
458 co_csdo_t *sdo, co_unsigned32_t ac);
459
462 co_csdo_t *sdo, const struct timespec *tp);
463
469 co_csdo_t *sdo, const struct can_msg *msg);
470
472// clang-format off
473LELY_CO_DEFINE_STATE(co_csdo_blk_up_ini_state,
474 .on_abort = &co_csdo_blk_up_ini_on_abort,
475 .on_time = &co_csdo_blk_up_ini_on_time,
478// clang-format on
479
482 co_csdo_t *sdo, co_unsigned32_t ac);
483
486 co_csdo_t *sdo, const struct timespec *tp);
487
493 co_csdo_t *sdo, const struct can_msg *msg);
494
496// clang-format off
497LELY_CO_DEFINE_STATE(co_csdo_blk_up_sub_state,
498 .on_abort = &co_csdo_blk_up_sub_on_abort,
499 .on_time = &co_csdo_blk_up_sub_on_time,
502// clang-format on
503
506 co_csdo_t *sdo, co_unsigned32_t ac);
507
510 co_csdo_t *sdo, const struct timespec *tp);
511
516 co_csdo_t *sdo, const struct can_msg *msg);
517
519// clang-format off
520LELY_CO_DEFINE_STATE(co_csdo_blk_up_end_state,
521 .on_abort = &co_csdo_blk_up_end_on_abort,
522 .on_time = &co_csdo_blk_up_end_on_time,
525// clang-format on
526
527#undef LELY_CO_DEFINE_STATE
528
535static co_csdo_state_t *co_csdo_abort_ind(co_csdo_t *sdo, co_unsigned32_t ac);
536
548static co_csdo_state_t *co_csdo_abort_res(co_csdo_t *sdo, co_unsigned32_t ac);
549
558static int co_csdo_dn_ind(co_csdo_t *sdo, co_unsigned16_t idx,
559 co_unsigned8_t subidx, const void *ptr, size_t n,
560 co_csdo_dn_con_t *con, void *data);
561
570static int co_csdo_up_ind(co_csdo_t *sdo, co_unsigned16_t idx,
571 co_unsigned8_t subidx, struct membuf *buf,
572 co_csdo_up_con_t *con, void *data);
573
580static void co_csdo_send_abort(co_csdo_t *sdo, co_unsigned32_t ac);
581
583static void co_csdo_send_dn_exp_req(co_csdo_t *sdo);
584
586static void co_csdo_send_dn_ini_req(co_csdo_t *sdo);
587
596static void co_csdo_send_dn_seg_req(
597 co_csdo_t *sdo, co_unsigned32_t n, int last);
598
600static void co_csdo_send_up_ini_req(co_csdo_t *sdo);
601
603static void co_csdo_send_up_seg_req(co_csdo_t *sdo);
604
606static void co_csdo_send_blk_dn_ini_req(co_csdo_t *sdo);
607
614static void co_csdo_send_blk_dn_sub_req(co_csdo_t *sdo, co_unsigned8_t seqno);
615
617static void co_csdo_send_blk_dn_end_req(co_csdo_t *sdo);
618
620static void co_csdo_send_blk_up_ini_req(co_csdo_t *sdo);
621
623static void co_csdo_send_start_up_req(co_csdo_t *sdo);
624
626static void co_csdo_send_blk_up_sub_res(co_csdo_t *sdo);
627
629static void co_csdo_send_blk_up_end_res(co_csdo_t *sdo);
630
638static void co_csdo_init_ini_req(
639 co_csdo_t *sdo, struct can_msg *msg, co_unsigned8_t cs);
640
648static void co_csdo_init_seg_req(
649 co_csdo_t *sdo, struct can_msg *msg, co_unsigned8_t cs);
650
657static void co_csdo_dn_dcf_dn_con(co_csdo_t *sdo, co_unsigned16_t idx,
658 co_unsigned8_t subidx, co_unsigned32_t ac, void *data);
659
660int
661co_dev_dn_req(co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx,
662 const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
663{
664 assert(dev);
665
666 int errc = get_errc();
667 struct co_sdo_req req = CO_SDO_REQ_INIT;
668
669 co_unsigned32_t ac = 0;
670
671 co_obj_t *obj = co_dev_find_obj(dev, idx);
672 if (!obj) {
673 ac = CO_SDO_AC_NO_OBJ;
674 goto done;
675 }
676
677 co_sub_t *sub = co_obj_find_sub(obj, subidx);
678 if (!sub) {
679 ac = CO_SDO_AC_NO_SUB;
680 goto done;
681 }
682
683 if (co_sdo_req_up(&req, ptr, n, &ac) == -1)
684 goto done;
685
686 ac = co_sub_dn_ind(sub, &req);
687
688done:
689 if (con)
690 con(NULL, idx, subidx, ac, data);
691
692 co_sdo_req_fini(&req);
693 set_errc(errc);
694 return 0;
695}
696
697int
698co_dev_dn_val_req(co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx,
699 co_unsigned16_t type, const void *val, co_csdo_dn_con_t *con,
700 void *data)
701{
702 assert(dev);
703
704 int errc = get_errc();
705 struct co_sdo_req req = CO_SDO_REQ_INIT;
706
707 co_unsigned32_t ac = 0;
708
709 co_obj_t *obj = co_dev_find_obj(dev, idx);
710 if (!obj) {
711 ac = CO_SDO_AC_NO_OBJ;
712 goto done;
713 }
714
715 co_sub_t *sub = co_obj_find_sub(obj, subidx);
716 if (!sub) {
717 ac = CO_SDO_AC_NO_SUB;
718 goto done;
719 }
720
721 if (co_sdo_req_up_val(&req, type, val, &ac) == -1)
722 goto done;
723
724 ac = co_sub_dn_ind(sub, &req);
725
726done:
727 if (con)
728 con(NULL, idx, subidx, ac, data);
729
730 co_sdo_req_fini(&req);
731 set_errc(errc);
732 return 0;
733}
734
735int
736co_dev_dn_dcf_req(co_dev_t *dev, const uint_least8_t *begin,
737 const uint_least8_t *end, co_csdo_dn_con_t *con, void *data)
738{
739 assert(dev);
740 assert(begin);
741 assert(end >= begin);
742
743 int errc = get_errc();
744 struct co_sdo_req req = CO_SDO_REQ_INIT;
745
746 co_unsigned16_t idx = 0;
747 co_unsigned8_t subidx = 0;
748 co_unsigned32_t ac = 0;
749
750 // Read the total number of sub-indices.
751 co_unsigned32_t n;
752 if (co_val_read(CO_DEFTYPE_UNSIGNED32, &n, begin, end) != 4) {
754 goto done;
755 }
756 begin += 4;
757
758 for (size_t i = 0; i < n && !ac; i++) {
759 idx = 0;
760 subidx = 0;
762 // Read the object index.
763 if (co_val_read(CO_DEFTYPE_UNSIGNED16, &idx, begin, end) != 2)
764 break;
765 begin += 2;
766 // Read the object sub-index.
767 if (co_val_read(CO_DEFTYPE_UNSIGNED8, &subidx, begin, end) != 1)
768 break;
769 begin += 1;
770 // Read the value size (in bytes).
771 co_unsigned32_t size;
772 if (co_val_read(CO_DEFTYPE_UNSIGNED32, &size, begin, end) != 4)
773 break;
774 begin += 4;
775 if (end - begin < (ptrdiff_t)size)
776 break;
777 co_obj_t *obj = co_dev_find_obj(dev, idx);
778
779 if (!obj) {
780 ac = CO_SDO_AC_NO_OBJ;
781 break;
782 }
783 co_sub_t *sub = co_obj_find_sub(obj, subidx);
784 if (!sub) {
785 ac = CO_SDO_AC_NO_SUB;
786 break;
787 }
788
789 // Write the value to the object dictionary.
790 co_sdo_req_clear(&req);
791 // cppcheck-suppress redundantAssignment
792 ac = 0;
793 if (!co_sdo_req_up(&req, begin, size, &ac))
794 ac = co_sub_dn_ind(sub, &req);
795
796 begin += size;
797 }
798
799done:
800 if (con)
801 con(NULL, idx, subidx, ac, data);
802
803 co_sdo_req_fini(&req);
804 set_errc(errc);
805 return 0;
806}
807
808int
809co_dev_up_req(const co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx,
810 co_csdo_up_con_t *con, void *data)
811{
812 assert(dev);
813
814 int errc = get_errc();
815 struct membuf buf = MEMBUF_INIT;
816 co_unsigned32_t ac = 0;
817
818 const co_obj_t *obj = co_dev_find_obj(dev, idx);
819 if (!obj) {
820 ac = CO_SDO_AC_NO_OBJ;
821 goto done;
822 }
823
824 const co_sub_t *sub = co_obj_find_sub(obj, subidx);
825 if (!sub) {
826 ac = CO_SDO_AC_NO_SUB;
827 goto done;
828 }
829
830 // If the object is an array, check whether the element exists.
832 && subidx > co_obj_get_val_u8(obj, 0)) {
834 goto done;
835 }
836
837 struct co_sdo_req req = CO_SDO_REQ_INIT;
838
839 ac = co_sub_up_ind(sub, &req);
840 if (!ac && req.size && !membuf_reserve(&buf, req.size))
841 ac = CO_SDO_AC_NO_MEM;
842
843 while (!ac && membuf_size(&buf) < req.size) {
844 membuf_write(&buf, req.buf, req.nbyte);
845 if (!co_sdo_req_last(&req))
846 ac = co_sub_up_ind(sub, &req);
847 }
848
849 co_sdo_req_fini(&req);
850
851done:
852 if (con)
853 con(NULL, idx, subidx, ac, ac ? NULL : buf.begin,
854 ac ? 0 : membuf_size(&buf), data);
855
857 set_errc(errc);
858 return 0;
859}
860
861void *
862__co_csdo_alloc(void)
863{
864 void *ptr = malloc(sizeof(struct __co_csdo));
865#if !LELY_NO_ERRNO
866 if (!ptr)
867 set_errc(errno2c(errno));
868#endif
869 return ptr;
870}
871
872void
873__co_csdo_free(void *ptr)
874{
875 free(ptr);
876}
877
878struct __co_csdo *
879__co_csdo_init(struct __co_csdo *sdo, can_net_t *net, co_dev_t *dev,
880 co_unsigned8_t num)
881{
882 assert(sdo);
883 assert(net);
884
885 int errc = 0;
886
887 if (!num || num > (dev ? CO_NUM_SDOS : CO_NUM_NODES)) {
888 errc = errnum2c(ERRNUM_INVAL);
889 goto error_param;
890 }
891
892 // Find the SDO client parameter in the object dictionary.
893 co_obj_t *obj_1280 =
894 dev ? co_dev_find_obj(dev, 0x1280 + num - 1) : NULL;
895 if (dev && !obj_1280) {
896 errc = errnum2c(ERRNUM_INVAL);
897 goto error_param;
898 }
899
900 sdo->net = net;
901 sdo->dev = dev;
902 sdo->num = num;
903
904 // Initialize the SDO parameter record with the default values.
905 sdo->par.n = 3;
906 sdo->par.id = num;
907 sdo->par.cobid_req = 0x600 + sdo->par.id;
908 sdo->par.cobid_res = 0x580 + sdo->par.id;
909
910 sdo->recv = can_recv_create();
911 if (!sdo->recv) {
912 errc = get_errc();
913 goto error_create_recv;
914 }
916
917 sdo->timeout = 0;
918
919 sdo->timer = can_timer_create();
920 if (!sdo->timer) {
921 errc = get_errc();
922 goto error_create_timer;
923 }
925
927
928 sdo->ac = 0;
929 sdo->idx = 0;
930 sdo->subidx = 0;
931 sdo->size = 0;
932
933 sdo->toggle = 0;
934 sdo->blksize = 0;
935 sdo->pst = 0;
936 sdo->ackseq = 0;
937 sdo->crc = 0;
938
939 membuf_init(&sdo->dn_buf, NULL, 0);
940 sdo->up_buf = NULL;
941#if LELY_NO_MALLOC
942 membuf_init(&sdo->buf, sdo->begin, CO_CSDO_MEMBUF_SIZE);
943 memset(sdo->begin, 0, CO_CSDO_MEMBUF_SIZE);
944#else
945 membuf_init(&sdo->buf, NULL, 0);
946#endif
947
948 sdo->dn_con = NULL;
949 sdo->dn_con_data = NULL;
950
951 sdo->dn_ind = NULL;
952 sdo->dn_ind_data = NULL;
953
954 sdo->up_con = NULL;
955 sdo->up_con_data = NULL;
956
957 sdo->up_ind = NULL;
958 sdo->up_ind_data = NULL;
959
960 sdo->dn_dcf = (struct co_csdo_dn_dcf){ 0 };
961
962 if (co_csdo_start(sdo) == -1) {
963 errc = get_errc();
964 goto error_start;
965 }
966
967 return sdo;
968
969 // co_csdo_stop(sdo);
970error_start:
972error_create_timer:
974error_create_recv:
975error_param:
976 set_errc(errc);
977 return NULL;
978}
979
980void
981__co_csdo_fini(struct __co_csdo *sdo)
982{
983 assert(sdo);
984 assert(sdo->num >= 1 && sdo->num <= CO_NUM_SDOS);
985
986 co_csdo_stop(sdo);
987
988 membuf_fini(&sdo->buf);
989
992}
993
994co_csdo_t *
995co_csdo_create(can_net_t *net, co_dev_t *dev, co_unsigned8_t num)
996{
997 trace("creating Client-SDO %d", num);
998
999 int errc = 0;
1000
1001 co_csdo_t *sdo = __co_csdo_alloc();
1002 if (!sdo) {
1003 errc = get_errc();
1004 goto error_alloc_sdo;
1005 }
1006
1007 if (!__co_csdo_init(sdo, net, dev, num)) {
1008 errc = get_errc();
1009 goto error_init_sdo;
1010 }
1011
1012 return sdo;
1013
1014error_init_sdo:
1015 __co_csdo_free(sdo);
1016error_alloc_sdo:
1017 set_errc(errc);
1018 return NULL;
1019}
1020
1021void
1023{
1024 if (csdo) {
1025 trace("destroying Client-SDO %d", csdo->num);
1026 __co_csdo_fini(csdo);
1027 __co_csdo_free(csdo);
1028 }
1029}
1030
1031int
1033{
1034 assert(sdo);
1035
1036 if (!co_csdo_is_stopped(sdo))
1037 return 0;
1038
1039 if (sdo->dev) {
1040 co_unsigned16_t idx_1280 = 0x1280 + sdo->num - 1;
1041 co_obj_t *obj_1280 = co_dev_find_obj(sdo->dev, idx_1280);
1042 assert(obj_1280);
1043 // Copy the SDO parameters.
1044 memset(&sdo->par, 0, sizeof(sdo->par));
1045 sdo->par.n = co_dev_get_val_u8(sdo->dev, idx_1280, 0);
1046 sdo->par.cobid_req = co_dev_get_val_u32(sdo->dev, idx_1280, 1);
1047 sdo->par.cobid_res = co_dev_get_val_u32(sdo->dev, idx_1280, 2);
1048 sdo->par.id = co_dev_get_val_u8(sdo->dev, idx_1280, 3);
1049 // Set the download indication function for the SDO parameter
1050 // record.
1051 co_obj_set_dn_ind(obj_1280, &co_1280_dn_ind, sdo);
1052 }
1053
1055
1056 if (co_csdo_update(sdo) == -1)
1057 goto error_update;
1058
1059 return 0;
1060
1061error_update:
1062 co_csdo_stop(sdo);
1063 return -1;
1064}
1065
1066void
1068{
1069 assert(sdo);
1070
1071 if (co_csdo_is_stopped(sdo))
1072 return;
1073
1074 // Abort any ongoing transfer.
1076
1077 can_timer_stop(sdo->timer);
1078 can_recv_stop(sdo->recv);
1079
1080 co_obj_t *obj_1280 = NULL;
1081 if (sdo->dev) {
1082 obj_1280 = co_dev_find_obj(sdo->dev, 0x1280 + sdo->num - 1);
1083 // Remove the download indication functions for the SDO
1084 // parameter record.
1085 co_obj_set_dn_ind(obj_1280, NULL, NULL);
1086 }
1087
1089}
1090
1091int
1093{
1094 assert(sdo);
1095
1096 return sdo->state == co_csdo_stopped_state;
1097}
1098
1099can_net_t *
1101{
1102 assert(sdo);
1103
1104 return sdo->net;
1105}
1106
1107co_dev_t *
1109{
1110 assert(sdo);
1111
1112 return sdo->dev;
1113}
1114
1115co_unsigned8_t
1117{
1118 assert(sdo);
1119
1120 return sdo->num;
1121}
1122
1123const struct co_sdo_par *
1125{
1126 assert(sdo);
1127
1128 return &sdo->par;
1129}
1130
1131int
1133{
1134 assert(sdo);
1135
1136 return sdo->timeout;
1137}
1138
1139void
1141{
1142 assert(sdo);
1143
1144 if (sdo->timeout && timeout <= 0)
1145 can_timer_stop(sdo->timer);
1146
1147 sdo->timeout = MAX(0, timeout);
1148}
1149
1150void
1151co_csdo_get_dn_ind(const co_csdo_t *sdo, co_csdo_ind_t **pind, void **pdata)
1152{
1153 assert(sdo);
1154
1155 if (pind)
1156 *pind = sdo->dn_ind;
1157 if (pdata)
1158 *pdata = sdo->dn_ind_data;
1159}
1160
1161void
1163{
1164 assert(sdo);
1165
1166 sdo->dn_ind = ind;
1167 sdo->dn_ind_data = data;
1168}
1169
1170void
1171co_csdo_get_up_ind(const co_csdo_t *sdo, co_csdo_ind_t **pind, void **pdata)
1172{
1173 assert(sdo);
1174
1175 if (pind)
1176 *pind = sdo->up_ind;
1177 if (pdata)
1178 *pdata = sdo->up_ind_data;
1179}
1180
1181void
1183{
1184 assert(sdo);
1185
1186 sdo->up_ind = ind;
1187 sdo->up_ind_data = data;
1188}
1189
1190int
1192{
1193 assert(sdo);
1194
1195 int valid_req = !(sdo->par.cobid_req & CO_SDO_COBID_VALID);
1196 int valid_res = !(sdo->par.cobid_res & CO_SDO_COBID_VALID);
1197 return valid_req && valid_res;
1198}
1199
1200int
1202{
1203 assert(sdo);
1204
1205 return sdo->state == co_csdo_wait_state;
1206}
1207
1208void
1209co_csdo_abort_req(co_csdo_t *sdo, co_unsigned32_t ac)
1210{
1211 assert(sdo);
1212
1213 co_csdo_emit_abort(sdo, ac);
1214}
1215
1216int
1217co_csdo_dn_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1218 const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
1219{
1220 assert(sdo);
1221
1222 if (co_csdo_dn_ind(sdo, idx, subidx, ptr, n, con, data) == -1)
1223 return -1;
1224
1225 trace("CSDO: %04X:%02X: initiate download", idx, subidx);
1226
1227 if (sdo->timeout)
1228 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1229 if (sdo->size && sdo->size <= 4)
1231 else
1234
1235 return 0;
1236}
1237
1238int
1239co_csdo_dn_val_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1240 co_unsigned16_t type, const void *val, co_csdo_dn_con_t *con,
1241 void *data)
1242{
1243 assert(sdo);
1244 struct membuf *buf = &sdo->buf;
1245
1246 // Obtain the size of the serialized value (which may be 0 for arrays).
1247 size_t n = co_val_write(type, val, NULL, NULL);
1248 if (!n && co_val_sizeof(type, val))
1249 return -1;
1250
1251 membuf_clear(buf);
1252 if (!membuf_reserve(buf, n))
1253 return -1;
1254 void *ptr = membuf_alloc(buf, &n);
1255
1256 if (co_val_write(type, val, ptr, (uint_least8_t *)ptr + n) != n)
1257 return -1;
1258
1259 return co_csdo_dn_req(sdo, idx, subidx, ptr, n, con, data);
1260}
1261
1262int
1263co_csdo_dn_dcf_req(co_csdo_t *sdo, const uint_least8_t *begin,
1264 const uint_least8_t *end, co_csdo_dn_con_t *con, void *data)
1265{
1266 assert(sdo);
1267 assert(begin);
1268 assert(end >= begin);
1269
1270 // Check whether the SDO exists, is valid and is in the waiting state.
1271 if (!co_csdo_is_valid(sdo) || !co_csdo_is_idle(sdo)) {
1273 return -1;
1274 }
1275
1276 co_unsigned32_t ac = 0;
1277
1278 // Read the total number of sub-indices.
1279 co_unsigned32_t n;
1282 begin += 4;
1283
1284 // Start the first SDO request.
1285 sdo->dn_dcf = (struct co_csdo_dn_dcf){ n, begin, end, con, data };
1286 co_csdo_dn_dcf_dn_con(sdo, 0, 0, ac, NULL);
1287
1288 return 0;
1289}
1290
1291int
1292co_csdo_up_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1293 co_csdo_up_con_t *con, void *data)
1294{
1295 assert(sdo);
1296
1297 if (co_csdo_up_ind(sdo, idx, subidx, NULL, con, data) == -1)
1298 return -1;
1299
1300 trace("CSDO: %04X:%02X: initiate upload", idx, subidx);
1301
1302 if (sdo->timeout)
1303 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1306
1307 return 0;
1308}
1309
1310int
1311co_csdo_blk_dn_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1312 const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
1313{
1314 assert(sdo);
1315
1316 if (co_csdo_dn_ind(sdo, idx, subidx, ptr, n, con, data) == -1)
1317 return -1;
1318
1319 trace("CSDO: %04X:%02X: initiate block download", idx, subidx);
1320
1321 if (sdo->timeout)
1322 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1325
1326 return 0;
1327}
1328
1329int
1330co_csdo_blk_dn_val_req(co_csdo_t *sdo, co_unsigned16_t idx,
1331 co_unsigned8_t subidx, co_unsigned16_t type, const void *val,
1332 co_csdo_dn_con_t *con, void *data)
1333{
1334 assert(sdo);
1335 struct membuf *buf = &sdo->buf;
1336
1337 // Obtain the size of the serialized value (which may be 0 for arrays).
1338 size_t n = co_val_write(type, val, NULL, NULL);
1339 if (!n && co_val_sizeof(type, val))
1340 return -1;
1341
1342 membuf_clear(buf);
1343 if (!membuf_reserve(buf, n))
1344 return -1;
1345 void *ptr = membuf_alloc(buf, &n);
1346
1347 if (co_val_write(type, val, ptr, (uint_least8_t *)ptr + n) != n)
1348 return -1;
1349
1350 return co_csdo_blk_dn_req(sdo, idx, subidx, ptr, n, con, data);
1351}
1352
1353int
1354co_csdo_blk_up_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1355 co_unsigned8_t pst, co_csdo_up_con_t *con, void *data)
1356{
1357 assert(sdo);
1358
1359 if (co_csdo_up_ind(sdo, idx, subidx, NULL, con, data) == -1)
1360 return -1;
1361
1362 trace("CSDO: %04X:%02X: initiate block upload", idx, subidx);
1363
1364 sdo->pst = pst;
1365 // Use the maximum block size by default.
1367
1368 if (sdo->timeout)
1369 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1372
1373 return 0;
1374}
1375
1376static int
1378{
1379 assert(sdo);
1380
1381 // Abort any ongoing transfer.
1383
1384 if (co_csdo_is_valid(sdo)) {
1385 uint_least32_t id = sdo->par.cobid_res;
1386 uint_least8_t flags = 0;
1387 if (id & CO_SDO_COBID_FRAME) {
1388 id &= CAN_MASK_EID;
1389 flags |= CAN_FLAG_IDE;
1390 } else {
1391 id &= CAN_MASK_BID;
1392 }
1393 can_recv_start(sdo->recv, sdo->net, id, flags);
1394 } else {
1395 can_recv_stop(sdo->recv);
1396 }
1397
1398 return 0;
1399}
1400
1401static co_unsigned32_t
1402co_1280_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
1403{
1404 assert(sub);
1405 assert(req);
1406 co_csdo_t *sdo = data;
1407 assert(sdo);
1408 assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1280 + sdo->num - 1);
1409
1410 co_unsigned16_t type = co_sub_get_type(sub);
1411 assert(!co_type_is_array(type));
1412
1413 union co_val val;
1414 co_unsigned32_t ac = 0;
1415 if (co_sdo_req_dn_val(req, type, &val, &ac) == -1)
1416 return ac;
1417
1418 switch (co_sub_get_subidx(sub)) {
1419 case 0: return CO_SDO_AC_NO_WRITE;
1420 case 1: {
1421 assert(type == CO_DEFTYPE_UNSIGNED32);
1422 co_unsigned32_t cobid = val.u32;
1423 co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
1424 if (cobid == cobid_old)
1425 return 0;
1426
1427 // The CAN-ID cannot be changed when the SDO is and remains
1428 // valid.
1429 int valid = !(cobid & CO_SDO_COBID_VALID);
1430 int valid_old = !(cobid_old & CO_SDO_COBID_VALID);
1431 uint_least32_t canid = cobid & CAN_MASK_EID;
1432 uint_least32_t canid_old = cobid_old & CAN_MASK_EID;
1433 if (valid && valid_old && canid != canid_old)
1434 return CO_SDO_AC_PARAM_VAL;
1435
1436 // A 29-bit CAN-ID is only valid if the frame bit is set.
1437 if (!(cobid & CO_SDO_COBID_FRAME)
1438 && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))
1439 return CO_SDO_AC_PARAM_VAL;
1440
1441 sdo->par.cobid_req = cobid;
1442 break;
1443 }
1444 case 2: {
1445 assert(type == CO_DEFTYPE_UNSIGNED32);
1446 co_unsigned32_t cobid = val.u32;
1447 co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
1448 if (cobid == cobid_old)
1449 return 0;
1450
1451 // The CAN-ID cannot be changed when the SDO is and remains
1452 // valid.
1453 int valid = !(cobid & CO_SDO_COBID_VALID);
1454 int valid_old = !(cobid_old & CO_SDO_COBID_VALID);
1455 uint_least32_t canid = cobid & CAN_MASK_EID;
1456 uint_least32_t canid_old = cobid_old & CAN_MASK_EID;
1457 if (valid && valid_old && canid != canid_old)
1458 return CO_SDO_AC_PARAM_VAL;
1459
1460 // A 29-bit CAN-ID is only valid if the frame bit is set.
1461 if (!(cobid & CO_SDO_COBID_FRAME)
1462 && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))
1463 return CO_SDO_AC_PARAM_VAL;
1464
1465 sdo->par.cobid_res = cobid;
1466 break;
1467 }
1468 case 3: {
1469 assert(type == CO_DEFTYPE_UNSIGNED8);
1470 co_unsigned8_t id = val.u8;
1471 co_unsigned8_t id_old = co_sub_get_val_u8(sub);
1472 if (id == id_old)
1473 return 0;
1474
1475 sdo->par.id = id;
1476 break;
1477 }
1478 default: return CO_SDO_AC_NO_SUB;
1479 }
1480
1481 co_sub_dn(sub, &val);
1482
1483 co_csdo_update(sdo);
1484 return 0;
1485}
1486
1487static int
1488co_csdo_recv(const struct can_msg *msg, void *data)
1489{
1490 assert(msg);
1491 co_csdo_t *sdo = data;
1492 assert(sdo);
1493
1494 // Ignore remote frames.
1495 if (msg->flags & CAN_FLAG_RTR)
1496 return 0;
1497
1498#if !LELY_NO_CANFD
1499 // Ignore CAN FD format frames.
1500 if (msg->flags & CAN_FLAG_EDL)
1501 return 0;
1502#endif
1503
1504 co_csdo_emit_recv(sdo, msg);
1505
1506 return 0;
1507}
1508
1509static int
1510co_csdo_timer(const struct timespec *tp, void *data)
1511{
1512 assert(tp);
1513 co_csdo_t *sdo = data;
1514 assert(sdo);
1515
1516 co_csdo_emit_time(sdo, tp);
1517
1518 return 0;
1519}
1520
1521static inline void
1523{
1524 assert(sdo);
1525 assert(sdo->state);
1526
1527 while (next) {
1528 co_csdo_state_t *prev = sdo->state;
1529 sdo->state = next;
1530
1531 if (prev->on_leave)
1532 prev->on_leave(sdo);
1533
1534 next = next->on_enter ? next->on_enter(sdo) : NULL;
1535 }
1536}
1537
1538static inline void
1539co_csdo_emit_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1540{
1541 assert(sdo);
1542 assert(sdo->state);
1543 assert(sdo->state->on_abort);
1544
1545 co_csdo_enter(sdo, sdo->state->on_abort(sdo, ac));
1546}
1547
1548static inline void
1549co_csdo_emit_time(co_csdo_t *sdo, const struct timespec *tp)
1550{
1551 assert(sdo);
1552 assert(sdo->state);
1553 assert(sdo->state->on_time);
1554
1555 co_csdo_enter(sdo, sdo->state->on_time(sdo, tp));
1556}
1557
1558static inline void
1559co_csdo_emit_recv(co_csdo_t *sdo, const struct can_msg *msg)
1560{
1561 assert(sdo);
1562 assert(sdo->state);
1563 assert(sdo->state->on_recv);
1564
1565 co_csdo_enter(sdo, sdo->state->on_recv(sdo, msg));
1566}
1567
1568static co_csdo_state_t *
1569co_csdo_stopped_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1570{
1571 (void)sdo;
1572 (void)ac;
1573
1574 return NULL;
1575}
1576
1577static co_csdo_state_t *
1578co_csdo_wait_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1579{
1580 (void)sdo;
1581 (void)ac;
1582
1583 return NULL;
1584}
1585
1586static co_csdo_state_t *
1588{
1589 assert(sdo);
1590 assert(msg);
1591
1592 if (msg->len < 1)
1594 co_unsigned8_t cs = msg->data[0];
1595
1596 co_unsigned32_t ac;
1597 switch (cs & CO_SDO_CS_MASK) {
1598 case CO_SDO_CS_ABORT:
1599 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1600 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1601 default: return NULL;
1602 }
1603}
1604
1605static co_csdo_state_t *
1607{
1608 (void)sdo;
1609
1610 can_timer_stop(sdo->timer);
1611
1612 return co_csdo_wait_state;
1613}
1614
1615static void
1617{
1618 assert(sdo);
1619
1620 co_csdo_dn_con_t *dn_con = sdo->dn_con;
1621 sdo->dn_con = NULL;
1622 void *dn_con_data = sdo->dn_con_data;
1623 sdo->dn_con_data = NULL;
1624
1625 co_csdo_up_con_t *up_con = sdo->up_con;
1626 sdo->up_con = NULL;
1627 void *up_con_data = sdo->up_con_data;
1628 sdo->up_con_data = NULL;
1629
1630 if (dn_con) {
1631 dn_con(sdo, sdo->idx, sdo->subidx, sdo->ac, dn_con_data);
1632 } else if (up_con) {
1633 struct membuf *buf = sdo->up_buf;
1634 assert(buf);
1635
1636 up_con(sdo, sdo->idx, sdo->subidx, sdo->ac,
1637 sdo->ac ? NULL : buf->begin,
1638 sdo->ac ? 0 : membuf_size(buf), up_con_data);
1639 }
1640}
1641
1642static co_csdo_state_t *
1643co_csdo_dn_ini_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1644{
1645 return co_csdo_abort_res(sdo, ac);
1646}
1647
1648static co_csdo_state_t *
1650{
1651 (void)tp;
1652
1654}
1655
1656static co_csdo_state_t *
1658{
1659 assert(sdo);
1660 assert(msg);
1661
1662 if (msg->len < 1)
1664 co_unsigned8_t cs = msg->data[0];
1665
1666 // Check the server command specifier.
1667 co_unsigned32_t ac;
1668 switch (cs & CO_SDO_CS_MASK) {
1669 case CO_SDO_SCS_DN_INI_RES: break;
1670 case CO_SDO_CS_ABORT:
1671 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1672 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1673 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1674 }
1675
1676 // Check the object index and sub-index.
1677 if (msg->len < 4)
1679 co_unsigned16_t idx = ldle_u16(msg->data + 1);
1680 co_unsigned8_t subidx = msg->data[3];
1681 if (idx != sdo->idx || subidx != sdo->subidx)
1683
1684 return co_csdo_dn_seg_state;
1685}
1686
1687static co_csdo_state_t *
1689{
1690 assert(sdo);
1691 struct membuf *buf = &sdo->dn_buf;
1692
1693 size_t n = sdo->size - membuf_size(buf);
1694 // 0-byte values cannot be sent using expedited transfer, so we need to
1695 // send one empty segment. We use the toggle bit to check if it was
1696 // sent.
1697 if (n || (!sdo->size && !sdo->toggle)) {
1698 if (sdo->timeout)
1699 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1700 co_csdo_send_dn_seg_req(sdo, MIN(n, 7), n <= 7);
1701 return NULL;
1702 } else {
1703 return co_csdo_abort_ind(sdo, 0);
1704 }
1705}
1706
1707static co_csdo_state_t *
1708co_csdo_dn_seg_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1709{
1710 return co_csdo_abort_res(sdo, ac);
1711}
1712
1713static co_csdo_state_t *
1715{
1716 (void)tp;
1717
1719}
1720
1721static co_csdo_state_t *
1723{
1724 assert(sdo);
1725 assert(msg);
1726
1727 if (msg->len < 1)
1729 co_unsigned8_t cs = msg->data[0];
1730
1731 // Check the server command specifier.
1732 co_unsigned32_t ac;
1733 switch (cs & CO_SDO_CS_MASK) {
1734 case CO_SDO_SCS_DN_SEG_RES: break;
1735 case CO_SDO_CS_ABORT:
1736 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1737 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1738 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1739 }
1740
1741 // Check the value of the toggle bit.
1742 if ((cs & CO_SDO_SEG_TOGGLE) == sdo->toggle)
1744
1745 return co_csdo_dn_seg_state;
1746}
1747
1748static co_csdo_state_t *
1749co_csdo_up_ini_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1750{
1751 return co_csdo_abort_res(sdo, ac);
1752}
1753
1754static co_csdo_state_t *
1756{
1757 (void)tp;
1758
1760}
1761
1762static co_csdo_state_t *
1764{
1765 assert(sdo);
1766 assert(msg);
1767 struct membuf *buf = sdo->up_buf;
1768 assert(buf);
1769
1770 if (msg->len < 1)
1772 co_unsigned8_t cs = msg->data[0];
1773
1774 // Check the server command specifier.
1775 co_unsigned32_t ac;
1776 switch (cs & CO_SDO_CS_MASK) {
1777 case CO_SDO_SCS_UP_INI_RES: break;
1778 case CO_SDO_CS_ABORT:
1779 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1780 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1781 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1782 }
1783
1784 // Check the object index and sub-index.
1785 if (msg->len < 4)
1787 co_unsigned16_t idx = ldle_u16(msg->data + 1);
1788 co_unsigned8_t subidx = msg->data[3];
1789 if (idx != sdo->idx || subidx != sdo->subidx)
1791
1792 // 0-pad the data bytes to handle servers which send CAN frames less
1793 // than 8 bytes.
1794 uint_least8_t data[4] = { 0 };
1795 memcpy(data, msg->data + 4, msg->len - 4);
1796
1797 // Obtain the size from the command specifier.
1798 int exp = !!(cs & CO_SDO_INI_SIZE_EXP);
1799 sdo->size = 0;
1800 if (exp) {
1801 if (cs & CO_SDO_INI_SIZE_IND)
1802 sdo->size = CO_SDO_INI_SIZE_EXP_GET(cs);
1803 else
1804 sdo->size = msg->len - 4;
1805 } else if (cs & CO_SDO_INI_SIZE_IND) {
1806 sdo->size = ldle_u32(data);
1807 }
1808
1809 // Allocate the buffer.
1810 if (sdo->size && !membuf_reserve(buf, sdo->size))
1812
1813 if (exp) {
1814 // Perform an expedited transfer.
1815 membuf_write(buf, data, sdo->size);
1816
1817 return co_csdo_abort_ind(sdo, 0);
1818 } else {
1819 if (sdo->size && sdo->up_ind)
1820 sdo->up_ind(sdo, sdo->idx, sdo->subidx, sdo->size, 0,
1821 sdo->up_ind_data);
1822 if (sdo->timeout)
1823 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1825 return co_csdo_up_seg_state;
1826 }
1827}
1828
1829static co_csdo_state_t *
1830co_csdo_up_seg_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
1831{
1832 return co_csdo_abort_res(sdo, ac);
1833}
1834
1835static co_csdo_state_t *
1837{
1838 (void)tp;
1839
1841}
1842
1843static co_csdo_state_t *
1845{
1846 assert(sdo);
1847 assert(msg);
1848 struct membuf *buf = sdo->up_buf;
1849 assert(buf);
1850
1851 if (msg->len < 1)
1853 co_unsigned8_t cs = msg->data[0];
1854
1855 // Check the server command specifier.
1856 co_unsigned32_t ac;
1857 switch (cs & CO_SDO_CS_MASK) {
1858 case CO_SDO_SCS_UP_SEG_RES: break;
1859 case CO_SDO_CS_ABORT:
1860 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1861 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1862 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1863 }
1864
1865 // Check the value of the toggle bit.
1866 if ((cs & CO_SDO_SEG_TOGGLE) == sdo->toggle)
1867 return co_csdo_up_seg_state;
1868
1869 // Obtain the size of the segment.
1870 size_t n = CO_SDO_SEG_SIZE_GET(cs);
1871 if (msg->len < 1 + n)
1873 int last = !!(cs & CO_SDO_SEG_LAST);
1874
1875 if (membuf_size(buf) + n > sdo->size)
1877
1878 // Copy the data to the buffer.
1879 assert(membuf_capacity(buf) >= n);
1880 membuf_write(buf, msg->data + 1, n);
1881
1882 if ((last || !(membuf_size(buf) % (CO_SDO_MAX_SEQNO * 7))) && sdo->size
1883 && sdo->up_ind)
1884 sdo->up_ind(sdo, sdo->idx, sdo->subidx, sdo->size,
1885 membuf_size(buf), sdo->up_ind_data);
1886 if (last) {
1887 if (sdo->size && membuf_size(buf) != sdo->size)
1889 return co_csdo_abort_ind(sdo, 0);
1890 } else {
1891 if (sdo->timeout)
1892 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1894 return co_csdo_up_seg_state;
1895 }
1896}
1897
1898static co_csdo_state_t *
1900{
1901 return co_csdo_abort_res(sdo, ac);
1902}
1903
1904static co_csdo_state_t *
1906{
1907 (void)tp;
1908
1910}
1911
1912static co_csdo_state_t *
1914{
1915 assert(sdo);
1916 assert(msg);
1917
1918 if (msg->len < 1)
1920 co_unsigned8_t cs = msg->data[0];
1921
1922 // Check the server command specifier.
1923 co_unsigned32_t ac;
1924 switch (cs & CO_SDO_CS_MASK) {
1925 case CO_SDO_SCS_BLK_DN_RES: break;
1926 case CO_SDO_CS_ABORT:
1927 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
1928 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
1929 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
1930 }
1931
1932 // Check the server subcommand.
1933 if ((cs & CO_SDO_SC_MASK) != CO_SDO_SC_INI_BLK)
1935
1936 // Check if the server supports generating a CRC.
1937 sdo->crc = !!(cs & CO_SDO_BLK_CRC);
1938
1939 // Check the object index and sub-index.
1940 if (msg->len < 4)
1942 co_unsigned16_t idx = ldle_u16(msg->data + 1);
1943 co_unsigned8_t subidx = msg->data[3];
1944 if (idx != sdo->idx || subidx != sdo->subidx)
1946
1947 // Load the number of segments per block.
1948 if (msg->len < 5)
1950 sdo->blksize = msg->data[4];
1951
1953}
1954
1955static co_csdo_state_t *
1957{
1958 assert(sdo);
1959 struct membuf *buf = &sdo->dn_buf;
1960
1961 size_t n = sdo->size - membuf_size(buf);
1962 if ((n > 0 && !sdo->blksize) || sdo->blksize > CO_SDO_MAX_SEQNO)
1964 sdo->blksize = (co_unsigned8_t)MIN((n + 6) / 7, sdo->blksize);
1965
1966 if (sdo->size && sdo->dn_ind)
1967 sdo->dn_ind(sdo, sdo->idx, sdo->subidx, sdo->size,
1968 membuf_size(buf), sdo->dn_ind_data);
1969 if (sdo->timeout)
1970 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
1971 if (n) {
1972 // Send all segments in the current block.
1973 for (co_unsigned8_t seqno = 1; seqno <= sdo->blksize; seqno++)
1974 co_csdo_send_blk_dn_sub_req(sdo, seqno);
1975 return NULL;
1976 } else {
1979 }
1980}
1981
1982static co_csdo_state_t *
1984{
1985 return co_csdo_abort_res(sdo, ac);
1986}
1987
1988static co_csdo_state_t *
1990{
1991 (void)tp;
1992
1994}
1995
1996static co_csdo_state_t *
1998{
1999 assert(sdo);
2000 assert(msg);
2001 struct membuf *buf = &sdo->dn_buf;
2002
2003 if (msg->len < 1)
2005 co_unsigned8_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_DN_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.
2018 if ((cs & CO_SDO_SC_MASK) != CO_SDO_SC_BLK_RES)
2020
2021 if (msg->len < 2)
2023 co_unsigned8_t ackseq = msg->data[1];
2024 if (ackseq < sdo->blksize) {
2025 // If the sequence number of the last segment that was
2026 // successfully received is smaller than the number of segments
2027 // in the block, resend the missing segments.
2028 size_t n = (membuf_size(buf) + 6) / 7;
2029 assert(n >= sdo->blksize);
2030 n -= sdo->blksize - ackseq;
2031 buf->cur = buf->begin + n * 7;
2032 }
2033
2034 // Read the number of segments in the next block.
2035 if (msg->len < 3)
2037 sdo->blksize = msg->data[2];
2038
2040}
2041
2042static co_csdo_state_t *
2044{
2045 return co_csdo_abort_res(sdo, ac);
2046}
2047
2048static co_csdo_state_t *
2050{
2051 (void)tp;
2052
2054}
2055
2056static co_csdo_state_t *
2058{
2059 assert(sdo);
2060 assert(msg);
2061
2062 if (msg->len < 1)
2064 co_unsigned8_t cs = msg->data[0];
2065
2066 // Check the server command specifier.
2067 co_unsigned32_t ac;
2068 switch (cs & CO_SDO_CS_MASK) {
2069 case CO_SDO_SCS_BLK_DN_RES: break;
2070 case CO_SDO_CS_ABORT:
2071 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
2072 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
2073 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
2074 }
2075
2076 // Check the server subcommand.
2077 if ((cs & CO_SDO_SC_MASK) != CO_SDO_SC_END_BLK)
2079
2080 return co_csdo_abort_ind(sdo, 0);
2081}
2082
2083static co_csdo_state_t *
2085{
2086 return co_csdo_abort_res(sdo, ac);
2087}
2088
2089static co_csdo_state_t *
2091{
2092 (void)tp;
2093
2095}
2096
2097static co_csdo_state_t *
2099{
2100 assert(sdo);
2101 assert(msg);
2102 struct membuf *buf = sdo->up_buf;
2103 assert(buf);
2104
2105 if (msg->len < 1)
2107 co_unsigned8_t cs = msg->data[0];
2108
2109 // Check the server command specifier.
2110 co_unsigned32_t ac;
2111 switch (cs & CO_SDO_CS_MASK) {
2113 // In case of a server-induced protocol switch, fall back to the
2114 // SDO upload protocol.
2115 return co_csdo_up_ini_on_recv(sdo, msg);
2116 case CO_SDO_SCS_BLK_UP_RES: break;
2117 case CO_SDO_CS_ABORT:
2118 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
2119 // If the block size is not supported, try again with half the
2120 // block size.
2121 if (ac == CO_SDO_AC_BLK_SIZE && sdo->blksize > 1) {
2122 // The first block size is 127, the second should be 64.
2123 sdo->blksize = (sdo->blksize + 1) / 2;
2124 if (sdo->timeout)
2125 can_timer_timeout(sdo->timer, sdo->net,
2126 sdo->timeout);
2128 return NULL;
2129 }
2130 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
2131 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
2132 }
2133
2134 // Check the server subcommand.
2135 if ((cs & 0x01) != CO_SDO_SC_INI_BLK)
2137
2138 // Check if the server supports generating a CRC.
2139 sdo->crc = !!(cs & CO_SDO_BLK_CRC);
2140
2141 // Check the object index and sub-index.
2142 if (msg->len < 4)
2144 co_unsigned16_t idx = ldle_u16(msg->data + 1);
2145 co_unsigned8_t subidx = msg->data[3];
2146 if (idx != sdo->idx || subidx != sdo->subidx)
2148
2149 // Obtain the data set size.
2150 sdo->size = 0;
2151 if (cs & CO_SDO_BLK_SIZE_IND) {
2152 // 0-pad the data bytes to handle servers which send CAN frames
2153 // less than 8 bytes.
2154 uint_least8_t data[4] = { 0 };
2155 memcpy(data, msg->data + 4, msg->len - 4);
2156 sdo->size = ldle_u32(data);
2157 }
2158
2159 // Allocate the buffer.
2160 if (sdo->size && !membuf_reserve(buf, sdo->size))
2162
2163 sdo->ackseq = 0;
2164
2165 if (sdo->timeout)
2166 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
2169}
2170
2171static co_csdo_state_t *
2173{
2174 return co_csdo_abort_res(sdo, ac);
2175}
2176
2177static co_csdo_state_t *
2179{
2180 (void)tp;
2181
2183}
2184
2185static co_csdo_state_t *
2187{
2188 assert(sdo);
2189 assert(msg);
2190 struct membuf *buf = sdo->up_buf;
2191 assert(buf);
2192
2193 if (msg->len < 1)
2195 co_unsigned8_t cs = msg->data[0];
2196
2197 if (cs == CO_SDO_CS_ABORT) {
2198 co_unsigned32_t ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
2199 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
2200 }
2201
2202 co_unsigned8_t seqno = cs & ~CO_SDO_SEQ_LAST;
2203 int last = !!(cs & CO_SDO_SEQ_LAST);
2204
2205 // Only accept sequential segments. Dropped segments will be resent
2206 // after the confirmation message.
2207 if (seqno == sdo->ackseq + 1) {
2208 sdo->ackseq++;
2209
2210 // Determine the number of bytes to copy.
2211 assert(sdo->size >= membuf_size(buf));
2212 size_t n = MIN(sdo->size - membuf_size(buf), 7);
2213 if (!last && n < 7)
2215
2216 // Copy the data to the buffer.
2217 assert(membuf_capacity(buf) >= n);
2218 membuf_write(buf, msg->data + 1, n);
2219 }
2220
2221 // If this is the last segment in the block, send a confirmation.
2222 if (seqno == sdo->blksize || last) {
2224 sdo->ackseq = 0;
2225 }
2226
2227 if (sdo->timeout)
2228 can_timer_timeout(sdo->timer, sdo->net, sdo->timeout);
2230}
2231
2232static co_csdo_state_t *
2234{
2235 return co_csdo_abort_res(sdo, ac);
2236}
2237
2238static co_csdo_state_t *
2240{
2241 (void)tp;
2242
2244}
2245
2246static co_csdo_state_t *
2248{
2249 assert(sdo);
2250 assert(msg);
2251 struct membuf *buf = sdo->up_buf;
2252 assert(buf);
2253
2254 if (msg->len < 1)
2256 co_unsigned8_t cs = msg->data[0];
2257
2258 // Check the server command specifier.
2259 co_unsigned32_t ac;
2260 switch (cs & CO_SDO_CS_MASK) {
2261 case CO_SDO_SCS_BLK_UP_RES: break;
2262 case CO_SDO_CS_ABORT:
2263 ac = msg->len < 8 ? 0 : ldle_u32(msg->data + 4);
2264 return co_csdo_abort_ind(sdo, ac ? ac : CO_SDO_AC_ERROR);
2265 default: return co_csdo_abort_res(sdo, CO_SDO_AC_NO_CS);
2266 }
2267
2268 // Check the server subcommand.
2269 if ((cs & CO_SDO_SC_MASK) != CO_SDO_SC_END_BLK)
2271
2272 // Check the total length.
2273 if (sdo->size && membuf_size(buf) != sdo->size)
2275
2276 // Check the number of bytes in the last segment.
2277 co_unsigned8_t n = sdo->size ? (sdo->size - 1) % 7 + 1 : 0;
2278 if (CO_SDO_BLK_SIZE_GET(cs) != n)
2280
2281 // Check the CRC.
2282 if (sdo->crc) {
2283 co_unsigned16_t crc = ldle_u16(msg->data + 1);
2284 if (crc != co_crc(0, (uint_least8_t *)buf->begin, sdo->size))
2286 }
2287
2289 return co_csdo_abort_ind(sdo, 0);
2290}
2291
2292static co_csdo_state_t *
2293co_csdo_abort_ind(co_csdo_t *sdo, co_unsigned32_t ac)
2294{
2295 assert(sdo);
2296
2297 sdo->ac = ac;
2298 return co_csdo_abort_state;
2299}
2300
2301static co_csdo_state_t *
2302co_csdo_abort_res(co_csdo_t *sdo, co_unsigned32_t ac)
2303{
2304 co_csdo_send_abort(sdo, ac);
2305 return co_csdo_abort_ind(sdo, ac);
2306}
2307
2308static int
2309co_csdo_dn_ind(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
2310 const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
2311{
2312 assert(sdo);
2313
2314 // Check whether the SDO exists, is valid and is in the waiting state.
2315 if (!co_csdo_is_valid(sdo) || !co_csdo_is_idle(sdo)) {
2317 return -1;
2318 }
2319
2320 sdo->ac = 0;
2321 sdo->idx = idx;
2322 sdo->subidx = subidx;
2323 sdo->size = ptr ? n : 0;
2324
2325 sdo->toggle = 0;
2326 sdo->blksize = 0;
2327 sdo->pst = 0;
2328 sdo->ackseq = 0;
2329 sdo->crc = 0;
2330
2331 // Casting away const is safe here since a download (write) request only
2332 // reads from the provided buffer.
2333 membuf_init(&sdo->dn_buf, (void *)ptr, n);
2334
2335 sdo->dn_con = con;
2336 sdo->dn_con_data = data;
2337
2338 sdo->up_con = NULL;
2339 sdo->up_con_data = NULL;
2340
2341 return 0;
2342}
2343
2344static int
2345co_csdo_up_ind(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
2346 struct membuf *buf, co_csdo_up_con_t *con, void *data)
2347{
2348 assert(sdo);
2349
2350 // Check whether the SDO exists, is valid and is in the waiting state.
2351 if (!co_csdo_is_valid(sdo) || !co_csdo_is_idle(sdo)) {
2353 return -1;
2354 }
2355
2356 sdo->ac = 0;
2357 sdo->idx = idx;
2358 sdo->subidx = subidx;
2359 sdo->size = 0;
2360
2361 sdo->toggle = 0;
2362 sdo->blksize = 0;
2363 sdo->pst = 0;
2364 sdo->ackseq = 0;
2365 sdo->crc = 0;
2366
2367 sdo->up_buf = buf ? buf : &sdo->buf;
2368 membuf_clear(sdo->up_buf);
2369
2370 sdo->dn_con = NULL;
2371 sdo->dn_con_data = NULL;
2372
2373 sdo->up_con = con;
2374 sdo->up_con_data = data;
2375
2376 return 0;
2377}
2378
2379static void
2380co_csdo_send_abort(co_csdo_t *sdo, co_unsigned32_t ac)
2381{
2382 assert(sdo);
2383
2384 struct can_msg msg;
2386 stle_u32(msg.data + 4, ac);
2387 can_net_send(sdo->net, &msg);
2388}
2389
2390static void
2392{
2393 assert(sdo);
2394 assert(sdo->size && sdo->size <= 4);
2395 struct membuf *buf = &sdo->dn_buf;
2396
2397 co_unsigned8_t cs = CO_SDO_CCS_DN_INI_REQ
2399
2400 struct can_msg msg;
2401 co_csdo_init_ini_req(sdo, &msg, cs);
2402 memcpy(msg.data + 4, buf->cur, sdo->size);
2403 buf->cur += sdo->size;
2404 can_net_send(sdo->net, &msg);
2405}
2406
2407static void
2409{
2410 assert(sdo);
2411 assert(!sdo->size || sdo->size > 4);
2412
2413 co_unsigned8_t cs = CO_SDO_CCS_DN_INI_REQ | CO_SDO_INI_SIZE_IND;
2414
2415 struct can_msg msg;
2416 co_csdo_init_ini_req(sdo, &msg, cs);
2417 stle_u32(msg.data + 4, sdo->size);
2418 can_net_send(sdo->net, &msg);
2419
2420 if (sdo->size && sdo->dn_ind)
2421 sdo->dn_ind(sdo, sdo->idx, sdo->subidx, sdo->size, 0,
2422 sdo->dn_ind_data);
2423}
2424
2425static void
2426co_csdo_send_dn_seg_req(co_csdo_t *sdo, co_unsigned32_t n, int last)
2427{
2428 assert(sdo);
2429 assert(n <= 7);
2430 struct membuf *buf = &sdo->dn_buf;
2431
2432 co_unsigned8_t cs = CO_SDO_CCS_DN_SEG_REQ | sdo->toggle
2434 sdo->toggle ^= CO_SDO_SEG_TOGGLE;
2435 if (last)
2436 cs |= CO_SDO_SEG_LAST;
2437
2438 struct can_msg msg;
2439 co_csdo_init_seg_req(sdo, &msg, cs);
2440 memcpy(msg.data + 1, buf->cur, n);
2441 buf->cur += n;
2442 can_net_send(sdo->net, &msg);
2443
2444 if ((last || !(membuf_size(buf) % (CO_SDO_MAX_SEQNO * 7))) && sdo->size
2445 && sdo->dn_ind)
2446 sdo->dn_ind(sdo, sdo->idx, sdo->subidx, sdo->size,
2447 membuf_size(buf), sdo->dn_ind_data);
2448}
2449
2450static void
2452{
2453 assert(sdo);
2454
2455 co_unsigned8_t cs = CO_SDO_CCS_UP_INI_REQ;
2456
2457 struct can_msg msg;
2458 co_csdo_init_ini_req(sdo, &msg, cs);
2459 can_net_send(sdo->net, &msg);
2460}
2461
2462static void
2464{
2465 assert(sdo);
2466
2467 co_unsigned8_t cs = CO_SDO_CCS_UP_SEG_REQ | sdo->toggle;
2468 sdo->toggle ^= CO_SDO_SEG_TOGGLE;
2469
2470 struct can_msg msg;
2471 co_csdo_init_seg_req(sdo, &msg, cs);
2472 can_net_send(sdo->net, &msg);
2473}
2474
2475static void
2477{
2478 assert(sdo);
2479
2480 co_unsigned8_t cs = CO_SDO_CCS_BLK_DN_REQ | CO_SDO_BLK_CRC
2482
2483 struct can_msg msg;
2484 co_csdo_init_ini_req(sdo, &msg, cs);
2485 stle_u32(msg.data + 4, sdo->size);
2486 can_net_send(sdo->net, &msg);
2487}
2488
2489static void
2490co_csdo_send_blk_dn_sub_req(co_csdo_t *sdo, co_unsigned8_t seqno)
2491{
2492 assert(sdo);
2493 assert(seqno && seqno <= CO_SDO_MAX_SEQNO);
2494 struct membuf *buf = &sdo->dn_buf;
2495
2496 size_t n = sdo->size - membuf_size(buf);
2497 int last = n <= 7;
2498 n = MIN(n, 7);
2499
2500 co_unsigned8_t cs = seqno;
2501 if (last)
2502 cs |= CO_SDO_SEQ_LAST;
2503
2504 struct can_msg msg;
2505 co_csdo_init_seg_req(sdo, &msg, cs);
2506 memcpy(msg.data + 1, buf->cur, n);
2507 buf->cur += n;
2508 can_net_send(sdo->net, &msg);
2509}
2510
2511static void
2513{
2514 assert(sdo);
2515 struct membuf *buf = &sdo->dn_buf;
2516
2517 // Compute the number of bytes in the last segment containing data.
2518 co_unsigned8_t n = sdo->size ? (sdo->size - 1) % 7 + 1 : 0;
2519
2520 co_unsigned8_t cs = CO_SDO_CCS_BLK_DN_REQ | CO_SDO_SC_END_BLK
2522
2523 co_unsigned16_t crc = sdo->crc
2524 ? co_crc(0, (uint_least8_t *)buf->begin, sdo->size)
2525 : 0;
2526
2527 struct can_msg msg;
2528 co_csdo_init_seg_req(sdo, &msg, cs);
2529 stle_u16(msg.data + 1, crc);
2530 can_net_send(sdo->net, &msg);
2531}
2532
2533static void
2535{
2536 assert(sdo);
2537
2538 co_unsigned8_t cs = CO_SDO_CCS_BLK_UP_REQ | CO_SDO_BLK_CRC
2540
2541 struct can_msg msg;
2542 co_csdo_init_ini_req(sdo, &msg, cs);
2543 msg.data[4] = sdo->blksize;
2544 msg.data[5] = sdo->pst;
2545 can_net_send(sdo->net, &msg);
2546}
2547
2548static void
2550{
2551 assert(sdo);
2552
2553 co_unsigned8_t cs = CO_SDO_CCS_BLK_UP_REQ | CO_SDO_SC_START_UP;
2554
2555 struct can_msg msg;
2556 co_csdo_init_seg_req(sdo, &msg, cs);
2557 can_net_send(sdo->net, &msg);
2558
2559 if (sdo->size && sdo->up_ind)
2560 sdo->up_ind(sdo, sdo->idx, sdo->subidx, sdo->size, 0,
2561 sdo->up_ind_data);
2562}
2563
2564static void
2566{
2567 assert(sdo);
2568 struct membuf *buf = sdo->up_buf;
2569 assert(buf);
2570
2571 co_unsigned8_t cs = CO_SDO_CCS_BLK_UP_REQ | CO_SDO_SC_BLK_RES;
2572
2573 struct can_msg msg;
2574 co_csdo_init_seg_req(sdo, &msg, cs);
2575 msg.data[1] = sdo->ackseq;
2576 msg.data[2] = sdo->blksize;
2577 can_net_send(sdo->net, &msg);
2578
2579 if (sdo->size && sdo->up_ind)
2580 sdo->up_ind(sdo, sdo->idx, sdo->subidx, sdo->size,
2581 membuf_size(buf), sdo->up_ind_data);
2582}
2583
2584static void
2586{
2587 assert(sdo);
2588
2589 co_unsigned8_t cs = CO_SDO_CCS_BLK_UP_REQ | CO_SDO_SC_END_BLK;
2590
2591 struct can_msg msg;
2592 co_csdo_init_seg_req(sdo, &msg, cs);
2593 can_net_send(sdo->net, &msg);
2594}
2595
2596static void
2597co_csdo_init_ini_req(co_csdo_t *sdo, struct can_msg *msg, co_unsigned8_t cs)
2598{
2599 assert(sdo);
2600 assert(msg);
2601
2602 *msg = (struct can_msg)CAN_MSG_INIT;
2603 msg->id = sdo->par.cobid_req;
2604 if (sdo->par.cobid_req & CO_SDO_COBID_FRAME) {
2605 msg->id &= CAN_MASK_EID;
2606 msg->flags |= CAN_FLAG_IDE;
2607 } else {
2608 msg->id &= CAN_MASK_BID;
2609 }
2610 msg->len = CAN_MAX_LEN;
2611 msg->data[0] = cs;
2612 stle_u16(msg->data + 1, sdo->idx);
2613 msg->data[3] = sdo->subidx;
2614}
2615
2616static void
2617co_csdo_init_seg_req(co_csdo_t *sdo, struct can_msg *msg, co_unsigned8_t cs)
2618{
2619 assert(sdo);
2620 assert(msg);
2621
2622 *msg = (struct can_msg)CAN_MSG_INIT;
2623 msg->id = sdo->par.cobid_req;
2624 if (sdo->par.cobid_req & CO_SDO_COBID_FRAME) {
2625 msg->id &= CAN_MASK_EID;
2626 msg->flags |= CAN_FLAG_IDE;
2627 } else {
2628 msg->id &= CAN_MASK_BID;
2629 }
2630 msg->len = CAN_MAX_LEN;
2631 msg->data[0] = cs;
2632}
2633
2634static void
2635co_csdo_dn_dcf_dn_con(co_csdo_t *sdo, co_unsigned16_t idx,
2636 co_unsigned8_t subidx, co_unsigned32_t ac, void *data)
2637{
2638 assert(sdo);
2639 assert(co_csdo_is_valid(sdo));
2640 assert(co_csdo_is_idle(sdo));
2641 struct co_csdo_dn_dcf *dcf = &sdo->dn_dcf;
2642
2643 if (!ac && dcf->n--) {
2644 idx = 0;
2645 subidx = 0;
2647 // Read the object index.
2648 // clang-format off
2649 if (co_val_read(CO_DEFTYPE_UNSIGNED16, &idx, dcf->begin,
2650 dcf->end) != 2)
2651 // clang-format on
2652 goto done;
2653 dcf->begin += 2;
2654 // Read the object sub-index.
2655 // clang-format off
2656 if (co_val_read(CO_DEFTYPE_UNSIGNED8, &subidx, dcf->begin,
2657 dcf->end) != 1)
2658 // clang-format on
2659 goto done;
2660 dcf->begin += 1;
2661 // Read the value size (in bytes).
2662 co_unsigned32_t size;
2663 // clang-format off
2664 if (co_val_read(CO_DEFTYPE_UNSIGNED32, &size, dcf->begin,
2665 dcf->end) != 4)
2666 // clang-format on
2667 goto done;
2668 dcf->begin += 4;
2669 if (dcf->end - dcf->begin < (ptrdiff_t)size)
2670 goto done;
2671 const void *ptr = dcf->begin;
2672 dcf->begin += size;
2673 // Submit the SDO download request. This cannot fail since we
2674 // already checked that the SDO exists, is valid and is idle.
2675 co_csdo_dn_req(sdo, idx, subidx, ptr, size,
2676 &co_csdo_dn_dcf_dn_con, NULL);
2677 return;
2678 }
2679
2680done:;
2681 co_csdo_dn_con_t *con = dcf->con;
2682 data = dcf->data;
2683
2684 *dcf = (struct co_csdo_dn_dcf){ 0 };
2685
2686 if (con)
2687 con(sdo, idx, subidx, ac, data);
2688}
2689
2690#endif // !LELY_NO_CO_CSDO
#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
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition dev.h:56
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
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:1402
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:1488
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:1559
static void co_csdo_send_dn_ini_req(co_csdo_t *sdo)
Sends a Client-SDO 'download initiate' request.
Definition csdo.c:2408
static void co_csdo_init_seg_req(co_csdo_t *sdo, struct can_msg *msg, co_unsigned8_t cs)
Initializes a Client-SDO download/upload segment request CAN frame.
Definition csdo.c:2617
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:1292
static void co_csdo_send_up_ini_req(co_csdo_t *sdo)
Sends a Client-SDO 'upload initiate' request.
Definition csdo.c:2451
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:809
void co_csdo_stop(co_csdo_t *sdo)
Stops a Client-SDO service.
Definition csdo.c:1067
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:1844
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:2247
static int co_csdo_timer(const struct timespec *tp, void *data)
The CAN timer callback function for a Client-SDO service.
Definition csdo.c:1510
static void co_csdo_dn_dcf_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac, void *data)
The confirmation function of a single SDO download request during a concise DCF download.
Definition csdo.c:2635
const struct __co_csdo_state co_csdo_state_t
An opaque CANopen Client-SDO state type.
Definition csdo.c:54
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:2098
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:1722
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:1201
static co_csdo_state_t *const co_csdo_blk_up_end_state
The 'block upload end' state.
Definition csdo.c:524
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:1830
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:2239
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:1836
static co_csdo_state_t *const co_csdo_blk_dn_end_state
The 'block download end' state.
Definition csdo.c:453
static void co_csdo_send_blk_up_ini_req(co_csdo_t *sdo)
Sends a Client-SDO 'block upload initiate' request.
Definition csdo.c:2534
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:2049
static void co_csdo_send_up_seg_req(co_csdo_t *sdo)
Sends a Client-SDO 'upload segment' request.
Definition csdo.c:2463
int co_csdo_is_stopped(const co_csdo_t *sdo)
Retuns 1 if the specified Client-SDO service is stopped, and 0 if not.
Definition csdo.c:1092
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:1217
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:698
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:2293
static co_csdo_state_t *const co_csdo_blk_up_ini_state
The 'block upload initiate' state.
Definition csdo.c:477
static int co_csdo_update(co_csdo_t *sdo)
Updates and (de)activates a Client-SDO service.
Definition csdo.c:1377
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:661
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:1587
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:1649
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:1899
int co_dev_dn_dcf_req(co_dev_t *dev, const uint_least8_t *begin, const uint_least8_t *end, co_csdo_dn_con_t *con, void *data)
Submits a series of download requests to a local device.
Definition csdo.c:736
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:2186
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:2178
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:1100
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:1522
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:1108
static co_csdo_state_t *const co_csdo_stopped_state
The 'stopped' state.
Definition csdo.c:254
static co_csdo_state_t * co_csdo_stopped_on_abort(co_csdo_t *sdo, co_unsigned32_t ac)
The 'abort' transition function of the 'stopped' state.
Definition csdo.c:1569
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:2565
void co_csdo_set_timeout(co_csdo_t *sdo, int timeout)
Sets the timeout of a Client-SDO.
Definition csdo.c:1140
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:2302
int co_csdo_get_timeout(const co_csdo_t *sdo)
Returns the timeout (in milliseconds) of a Client-SDO.
Definition csdo.c:1132
void co_csdo_destroy(co_csdo_t *csdo)
Destroys a CANopen Client-SDO service.
Definition csdo.c:1022
static void co_csdo_send_blk_up_end_res(co_csdo_t *sdo)
Sends a Client-SDO 'block upload end' response.
Definition csdo.c:2585
int co_csdo_start(co_csdo_t *sdo)
Starts a Client-SDO service.
Definition csdo.c:1032
static co_csdo_state_t *const co_csdo_dn_seg_state
The 'download segment' state.
Definition csdo.c:335
int co_csdo_blk_up_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned8_t pst, co_csdo_up_con_t *con, void *data)
Submits a block upload request to a remote Server-SDO.
Definition csdo.c:1354
static co_csdo_state_t *const co_csdo_abort_state
The 'abort transfer' state.
Definition csdo.c:284
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:1311
int co_csdo_blk_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 block download request to a remote Server-SDO.
Definition csdo.c:1330
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:1182
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:2172
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:1549
static co_csdo_state_t *const co_csdo_up_ini_state
The 'upload initiate' state.
Definition csdo.c:356
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:1606
static void co_csdo_init_ini_req(co_csdo_t *sdo, struct can_msg *msg, co_unsigned8_t cs)
Initializes a Client-SDO download/upload initiate request CAN frame.
Definition csdo.c:2597
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:1657
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:1209
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:1643
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:1708
int co_csdo_dn_dcf_req(co_csdo_t *sdo, const uint_least8_t *begin, const uint_least8_t *end, co_csdo_dn_con_t *con, void *data)
Submits a series of download requests to a remote Server-SDO.
Definition csdo.c:1263
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:2057
static co_csdo_state_t *const co_csdo_wait_state
The 'waiting' state.
Definition csdo.c:270
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:1171
static void co_csdo_send_blk_dn_end_req(co_csdo_t *sdo)
Sends a Client-SDO 'block download end' request.
Definition csdo.c:2512
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:1688
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:1124
static co_csdo_state_t *const co_csdo_blk_dn_ini_state
The 'block download initiate' state.
Definition csdo.c:401
static int co_csdo_up_ind(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, struct membuf *buf, 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:2345
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:1905
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:1539
static co_csdo_state_t *const co_csdo_blk_up_sub_state
The 'block upload sub-block' state.
Definition csdo.c:501
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:2090
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:2233
static void co_csdo_send_start_up_req(co_csdo_t *sdo)
Sends a Client-SDO 'start upload' request.
Definition csdo.c:2549
static void co_csdo_send_dn_seg_req(co_csdo_t *sdo, co_unsigned32_t n, int last)
Sends a Client-SDO 'download segment' request.
Definition csdo.c:2426
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:1578
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:1989
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:1763
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:1162
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:2309
static void co_csdo_send_blk_dn_ini_req(co_csdo_t *sdo)
Sends a Client-SDO 'block download initiate' request.
Definition csdo.c:2476
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:995
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:1755
static co_csdo_state_t *const co_csdo_blk_dn_sub_state
The 'block download sub-block' state.
Definition csdo.c:429
co_unsigned8_t co_csdo_get_num(const co_csdo_t *sdo)
Returns the SDO number of a Client-SDO.
Definition csdo.c:1116
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:1983
static co_csdo_state_t *const co_csdo_dn_ini_state
The 'download initiate' state.
Definition csdo.c:308
int co_csdo_is_valid(const co_csdo_t *sdo)
Returns 1 of the COB-IDs of the specified Client-SDO service are valid, and 0 if not.
Definition csdo.c:1191
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:1151
static void co_csdo_send_dn_exp_req(co_csdo_t *sdo)
Sends a Client-SDO 'download initiate' (expedited) request.
Definition csdo.c:2391
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:1239
static void co_csdo_abort_on_leave(co_csdo_t *sdo)
The exit function of the 'abort transfer' state.
Definition csdo.c:1616
static void co_csdo_send_abort(co_csdo_t *sdo, co_unsigned32_t ac)
Sends an abort transfer request.
Definition csdo.c:2380
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:2084
static void co_csdo_send_blk_dn_sub_req(co_csdo_t *sdo, co_unsigned8_t seqno)
Sends a Client-SDO 'block download sub-block' request.
Definition csdo.c:2490
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:1997
static co_csdo_state_t *const co_csdo_up_seg_state
The 'upload segment' state.
Definition csdo.c:377
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:1749
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:1714
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:1956
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:1913
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:2043
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 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
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition errnum.h:424
struct __co_csdo co_csdo_t
An opaque CANopen Client-SDO service type.
Definition co.h:78
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
#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_REQ_INIT
The static initializer for struct co_sdo_req.
Definition sdo.h:206
#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
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:287
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:258
#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_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
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
#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
#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
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
size_t membuf_capacity(const struct membuf *buf)
Returns the number of unused bytes remaining in a memory buffer.
Definition membuf.h:185
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_alloc(struct membuf *buf, size_t *size)
Creates region of *size bytes in a memory buffer, starting at the current position indicator given by...
Definition membuf.h:211
void membuf_clear(struct membuf *buf)
Clears a memory buffer.
Definition membuf.h:169
#define MEMBUF_INIT
The static initializer for struct membuf.
Definition membuf.h:46
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_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....
This header file is part of the C11 and POSIX compatibility library; it includes <string....
A CANopen Client-SDO state.
Definition csdo.c:207
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:209
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:238
void(* on_leave)(co_csdo_t *sdo)
A pointer to the function invoked when the current state is left.
Definition csdo.c:240
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:228
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:219
A CANopen Client-SDO.
Definition csdo.c:71
co_unsigned8_t ackseq
The sequence number of the last successfully received segment.
Definition csdo.c:103
void * up_ind_data
A pointer to user-specified data for up_ind.
Definition csdo.c:137
void * dn_con_data
A pointer to user-specified data for dn_con.
Definition csdo.c:125
can_timer_t * timer
A pointer to the CAN timer.
Definition csdo.c:85
co_csdo_ind_t * up_ind
A pointer to the upload progress indication function.
Definition csdo.c:135
void * up_con_data
A pointer to user-specified data for up_con.
Definition csdo.c:133
co_unsigned8_t pst
The protocol switch threshold.
Definition csdo.c:101
co_unsigned8_t subidx
The current object sub-index.
Definition csdo.c:93
int timeout
The SDO timeout (in milliseconds).
Definition csdo.c:83
co_unsigned16_t idx
The current object index.
Definition csdo.c:91
co_unsigned8_t num
The SDO number.
Definition csdo.c:77
co_csdo_up_con_t * up_con
A pointer to the upload confirmation function.
Definition csdo.c:131
co_unsigned8_t blksize
The number of segments per block.
Definition csdo.c:99
void * dn_ind_data
A pointer to user-specified data for dn_ind.
Definition csdo.c:129
struct membuf * up_buf
A pointer to the memory buffer used for upload requests.
Definition csdo.c:109
co_csdo_ind_t * dn_ind
A pointer to the download progress indication function.
Definition csdo.c:127
co_unsigned8_t toggle
The current value of the toggle bit.
Definition csdo.c:97
struct co_csdo_dn_dcf dn_dcf
The state of the concise DCF download request.
Definition csdo.c:139
co_csdo_dn_con_t * dn_con
A pointer to the download confirmation function.
Definition csdo.c:123
co_unsigned32_t size
The data set size (in bytes).
Definition csdo.c:95
co_unsigned32_t ac
The current abort code.
Definition csdo.c:89
struct membuf buf
The memory buffer used for storing serialized values in the absence of a user-specified buffer.
Definition csdo.c:114
struct membuf dn_buf
The memory buffer used for download requests.
Definition csdo.c:107
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition csdo.c:81
co_csdo_state_t * state
A pointer to the current state.
Definition csdo.c:87
struct co_sdo_par par
The SDO parameter record.
Definition csdo.c:79
can_net_t * net
A pointer to a CAN network interface.
Definition csdo.c:73
co_dev_t * dev
A pointer to a CANopen device.
Definition csdo.c:75
unsigned crc
A flag indicating whether a CRC should be generated.
Definition csdo.c:105
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
The state of a concise DCF download request.
Definition csdo.c:57
const uint_least8_t * end
A pointer to one past the last byte in the concise DCF.
Definition csdo.c:63
void * data
A pointer to user-specified data for con.
Definition csdo.c:67
co_unsigned32_t n
The number of remaining entries in the concise DCF.
Definition csdo.c:59
co_csdo_dn_con_t * con
A pointer to the download confirmation function.
Definition csdo.c:65
const uint_least8_t * begin
A pointer to the next byte in the concise DCF.
Definition csdo.c:61
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 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
char * end
A pointer to one past the last byte in the buffer.
Definition membuf.h:42
char * begin
A pointer to the first byte in the buffer.
Definition membuf.h:40
char * cur
A pointer to one past the last byte written to the buffer.
Definition membuf.h:38
A time type with nanosecond resolution.
Definition time.h:88
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition type.h:47
int co_type_is_array(co_unsigned16_t type)
Returns 1 if the specified (static) data type is an array, and 0 if not.
Definition type.c:40
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition type.h:44
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition type.h:50
A union of the CANopen static data types.
Definition val.h:273
This header file is part of the CANopen library; it contains the CANopen value declarations.
size_t co_val_read(co_unsigned16_t type, void *val, const uint_least8_t *begin, const uint_least8_t *end)
Reads a value of the specified data type from a memory buffer.
Definition val.c:451
size_t co_val_write(co_unsigned16_t type, const void *val, uint_least8_t *begin, uint_least8_t *end)
Writes a value of the specified data type to a memory buffer.
Definition val.c:791
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:269