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