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