Lely core libraries  2.2.5
nmt_boot.c
Go to the documentation of this file.
1 
24 #include "co.h"
25 
26 #ifndef LELY_NO_CO_MASTER
27 
28 #include "nmt_boot.h"
29 #include <lely/co/dev.h>
30 #include <lely/co/obj.h>
31 #include <lely/co/val.h>
32 #include <lely/util/diag.h>
33 #include <lely/util/time.h>
34 
35 #include <assert.h>
36 #include <inttypes.h>
37 #include <stdlib.h>
38 
39 #ifndef LELY_CO_NMT_BOOT_WAIT_TIMEOUT
40 #define LELY_CO_NMT_BOOT_WAIT_TIMEOUT 1000
42 #endif
43 
44 #ifndef LELY_CO_NMT_BOOT_SDO_RETRY
45 #define LELY_CO_NMT_BOOT_SDO_RETRY 3
47 #endif
48 
49 #ifndef LELY_CO_NMT_BOOT_RTR_TIMEOUT
50 #define LELY_CO_NMT_BOOT_RTR_TIMEOUT 100
52 #endif
53 
54 #ifndef LELY_CO_NMT_BOOT_RESET_TIMEOUT
55 
59 #define LELY_CO_NMT_BOOT_RESET_TIMEOUT 1000
60 #endif
61 
62 #ifndef LELY_CO_NMT_BOOT_CHECK_TIMEOUT
63 
67 #define LELY_CO_NMT_BOOT_CHECK_TIMEOUT 100
68 #endif
69 
70 struct __co_nmt_boot_state;
73 
75 struct __co_nmt_boot {
89  co_unsigned8_t id;
91  int timeout;
95  struct timespec start;
97  co_unsigned32_t assignment;
99  co_unsigned16_t ms;
101  struct co_sdo_req req;
103  int retry;
105  co_unsigned8_t st;
107  char es;
108 };
109 
115 static int co_nmt_boot_recv(const struct can_msg *msg, void *data);
116 
122 static int co_nmt_boot_timer(const struct timespec *tp, void *data);
123 
130 static void co_nmt_boot_dn_con(co_csdo_t *sdo, co_unsigned16_t idx,
131  co_unsigned8_t subidx, co_unsigned32_t ac, void *data);
132 
139 static void co_nmt_boot_up_con(co_csdo_t *sdo, co_unsigned16_t idx,
140  co_unsigned8_t subidx, co_unsigned32_t ac, const void *ptr,
141  size_t n, void *data);
142 
149 static void co_nmt_boot_cfg_con(co_nmt_t *nmt, co_unsigned8_t id,
150  co_unsigned32_t ac, void *data);
151 
156 static void co_nmt_boot_enter(co_nmt_boot_t *boot, co_nmt_boot_state_t *next);
157 
165 static inline void co_nmt_boot_emit_recv(
166  co_nmt_boot_t *boot, const struct can_msg *msg);
167 
175 static inline void co_nmt_boot_emit_time(
176  co_nmt_boot_t *boot, const struct timespec *tp);
177 
185 static inline void co_nmt_boot_emit_dn_con(
186  co_nmt_boot_t *boot, co_unsigned32_t ac);
187 
197 static inline void co_nmt_boot_emit_up_con(co_nmt_boot_t *boot,
198  co_unsigned32_t ac, const void *ptr, size_t n);
199 
207 static inline void co_nmt_boot_emit_cfg_con(
208  co_nmt_boot_t *boot, co_unsigned32_t ac);
209 
213  co_nmt_boot_state_t *(*on_enter)(co_nmt_boot_t *boot);
223  co_nmt_boot_state_t *(*on_recv)(
224  co_nmt_boot_t *boot, const struct can_msg *msg);
233  co_nmt_boot_state_t *(*on_time)(
234  co_nmt_boot_t *boot, const struct timespec *tp);
244  co_nmt_boot_state_t *(*on_dn_con)(
245  co_nmt_boot_t *boot, co_unsigned32_t ac);
257  co_nmt_boot_state_t *(*on_up_con)(co_nmt_boot_t *boot,
258  co_unsigned32_t ac, const void *ptr, size_t n);
268  co_nmt_boot_state_t *(*on_cfg_con)(
269  co_nmt_boot_t *boot, co_unsigned32_t ac);
271  void (*on_leave)(co_nmt_boot_t *boot);
272 };
273 
274 #define LELY_CO_DEFINE_STATE(name, ...) \
275  static co_nmt_boot_state_t *const name = \
276  &(co_nmt_boot_state_t){ __VA_ARGS__ };
277 
280  co_nmt_boot_t *boot, const struct timespec *tp);
281 
283 // clang-format off
284 LELY_CO_DEFINE_STATE(co_nmt_boot_wait_state,
285  .on_time = &co_nmt_boot_wait_on_time
286 )
287 // clang-format on
288 
291 
293 // clang-format off
294 LELY_CO_DEFINE_STATE(co_nmt_boot_abort_state,
295  .on_enter = &co_nmt_boot_abort_on_enter
296 )
297 // clang-format on
298 
301 
303 static void co_nmt_boot_error_on_leave(co_nmt_boot_t *boot);
304 
306 // clang-format off
307 LELY_CO_DEFINE_STATE(co_nmt_boot_error_state,
308  .on_enter = &co_nmt_boot_error_on_enter,
309  .on_leave = &co_nmt_boot_error_on_leave
310 )
311 // clang-format on
312 
315  co_nmt_boot_t *boot);
316 
322  co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
323  size_t n);
324 
326 // clang-format off
327 LELY_CO_DEFINE_STATE(co_nmt_boot_chk_device_type_state,
330 )
331 // clang-format on
332 
335  co_nmt_boot_t *boot);
336 
342  co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
343  size_t n);
344 
346 // clang-format off
347 LELY_CO_DEFINE_STATE(co_nmt_boot_chk_vendor_id_state,
350 )
351 // clang-format on
352 
355  co_nmt_boot_t *boot);
356 
362  co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
363  size_t n);
364 
366 // clang-format off
367 LELY_CO_DEFINE_STATE(co_nmt_boot_chk_product_code_state,
370 )
371 // clang-format on
372 
375  co_nmt_boot_t *boot);
376 
382  co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
383  size_t n);
384 
386 // clang-format off
387 LELY_CO_DEFINE_STATE(co_nmt_boot_chk_revision_state,
390 )
391 // clang-format on
392 
395  co_nmt_boot_t *boot);
396 
402  co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
403  size_t n);
404 
406 // clang-format off
407 LELY_CO_DEFINE_STATE(co_nmt_boot_chk_serial_nr_state,
410 )
411 // clang-format on
412 
415 
420  co_nmt_boot_t *boot, const struct can_msg *msg);
421 
424  co_nmt_boot_t *boot, const struct timespec *tp);
425 
428 
430 // clang-format off
431 LELY_CO_DEFINE_STATE(co_nmt_boot_chk_node_state,
432  .on_enter = &co_nmt_boot_chk_node_on_enter,
433  .on_recv = &co_nmt_boot_chk_node_on_recv,
434  .on_time = &co_nmt_boot_chk_node_on_time,
435  .on_leave = &co_nmt_boot_chk_node_on_leave
436 )
437 // clang-format on
438 
441  co_nmt_boot_t *boot);
442 
448  co_nmt_boot_t *boot, const struct can_msg *msg);
449 
452  co_nmt_boot_t *boot, const struct timespec *tp);
453 
455 // clang-format off
456 LELY_CO_DEFINE_STATE(co_nmt_boot_reset_comm_state,
457  .on_enter = &co_nmt_boot_reset_comm_on_enter,
458  .on_recv = &co_nmt_boot_reset_comm_on_recv,
460 )
461 // clang-format on
462 
465 
471  co_unsigned32_t ac, const void *ptr, size_t n);
472 
474 // clang-format off
475 LELY_CO_DEFINE_STATE(co_nmt_boot_chk_sw_state,
476  .on_enter = &co_nmt_boot_chk_sw_on_enter,
477  .on_up_con = &co_nmt_boot_chk_sw_on_up_con
478 )
479 // clang-format on
480 
483 
489  co_nmt_boot_t *boot, co_unsigned32_t ac);
490 
496  co_unsigned32_t ac, const void *ptr, size_t n);
497 
499 // clang-format off
500 LELY_CO_DEFINE_STATE(co_nmt_boot_stop_prog_state,
501  .on_enter = &co_nmt_boot_stop_prog_on_enter,
502  .on_dn_con = &co_nmt_boot_stop_prog_on_dn_con,
503  .on_up_con = &co_nmt_boot_stop_prog_on_up_con
504 )
505 // clang-format on
506 
509  co_nmt_boot_t *boot);
510 
516  co_nmt_boot_t *boot, co_unsigned32_t ac);
517 
519 // clang-format off
520 LELY_CO_DEFINE_STATE(co_nmt_boot_clear_prog_state,
521  .on_enter = &co_nmt_boot_clear_prog_on_enter,
523 )
524 // clang-format on
525 
528  co_nmt_boot_t *boot);
529 
535  co_nmt_boot_t *boot, co_unsigned32_t ac);
536 
538 // clang-format off
539 LELY_CO_DEFINE_STATE(co_nmt_boot_blk_dn_prog_state,
542 )
543 // clang-format on
544 
547 
553  co_nmt_boot_t *boot, co_unsigned32_t ac);
554 
556 // clang-format off
557 LELY_CO_DEFINE_STATE(co_nmt_boot_dn_prog_state,
558  .on_enter = &co_nmt_boot_dn_prog_on_enter,
559  .on_dn_con = &co_nmt_boot_dn_prog_on_dn_con
560 )
561 // clang-format on
562 
565  co_nmt_boot_t *boot);
566 
569  co_nmt_boot_t *boot, const struct timespec *tp);
570 
576  co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
577  size_t n);
578 
580 // clang-format off
581 LELY_CO_DEFINE_STATE(co_nmt_boot_wait_flash_state,
582  .on_enter = &co_nmt_boot_wait_flash_on_enter,
583  .on_time = &co_nmt_boot_wait_flash_on_time,
585 )
586 // clang-format on
587 
590 
596  co_unsigned32_t ac, const void *ptr, size_t n);
597 
599 // clang-format off
600 LELY_CO_DEFINE_STATE(co_nmt_boot_chk_prog_state,
601  .on_enter = &co_nmt_boot_chk_prog_on_enter,
602  .on_up_con = &co_nmt_boot_chk_prog_on_up_con
603 )
604 // clang-format on
605 
608  co_nmt_boot_t *boot);
609 
615  co_nmt_boot_t *boot, co_unsigned32_t ac);
616 
618 // clang-format off
619 LELY_CO_DEFINE_STATE(co_nmt_boot_start_prog_state,
620  .on_enter = &co_nmt_boot_start_prog_on_enter,
622 )
623 // clang-format on
624 
627 
633  co_nmt_boot_t *boot, const struct timespec *tp);
634 
640  co_unsigned32_t ac, const void *ptr, size_t n);
641 
646 // clang-format off
647 LELY_CO_DEFINE_STATE(co_nmt_boot_wait_prog_state,
648  .on_enter = &co_nmt_boot_wait_prog_on_enter,
649  .on_time = &co_nmt_boot_wait_prog_on_time,
650  .on_up_con = &co_nmt_boot_wait_prog_on_up_con
651 )
652 // clang-format on
653 
656  co_nmt_boot_t *boot);
657 
663  co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
664  size_t n);
665 
669 // clang-format off
670 LELY_CO_DEFINE_STATE(co_nmt_boot_chk_cfg_date_state,
673 )
674 // clang-format on
675 
681  co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
682  size_t n);
683 
687 // clang-format off
688 LELY_CO_DEFINE_STATE(co_nmt_boot_chk_cfg_time_state,
690 )
691 // clang-format on
692 
695 
701  co_nmt_boot_t *boot, co_unsigned32_t ac);
702 
706 // clang-format off
707 LELY_CO_DEFINE_STATE(co_nmt_boot_up_cfg_state,
708  .on_enter = &co_nmt_boot_up_cfg_on_enter,
709  .on_cfg_con = &co_nmt_boot_up_cfg_on_cfg_con
710 )
711 // clang-format on
712 
715 
721  co_nmt_boot_t *boot, const struct can_msg *msg);
722 
725  co_nmt_boot_t *boot, const struct timespec *tp);
726 
728 // clang-format off
729 LELY_CO_DEFINE_STATE(co_nmt_boot_ec_state,
730  .on_enter = &co_nmt_boot_ec_on_enter,
731  .on_recv = &co_nmt_boot_ec_on_recv,
732  .on_time = &co_nmt_boot_ec_on_time
733 )
734 // clang-format on
735 
736 #undef LELY_CO_DEFINE_STATE
737 
750 static int co_nmt_boot_dn(co_nmt_boot_t *boot, co_unsigned16_t idx,
751  co_unsigned8_t subidx, co_unsigned16_t type, const void *val);
752 
763 static int co_nmt_boot_up(co_nmt_boot_t *boot, co_unsigned16_t idx,
764  co_unsigned8_t subidx);
765 
779 static int co_nmt_boot_chk(co_nmt_boot_t *boot, co_unsigned16_t idx,
780  co_unsigned8_t subidx, const void *ptr, size_t n);
781 
787 static int co_nmt_boot_send_rtr(co_nmt_boot_t *boot);
788 
789 void *
790 __co_nmt_boot_alloc(void)
791 {
792  void *ptr = malloc(sizeof(struct __co_nmt_boot));
793  if (!ptr)
794  set_errc(errno2c(errno));
795  return ptr;
796 }
797 
798 void
799 __co_nmt_boot_free(void *ptr)
800 {
801  free(ptr);
802 }
803 
804 struct __co_nmt_boot *
805 __co_nmt_boot_init(struct __co_nmt_boot *boot, can_net_t *net, co_dev_t *dev,
806  co_nmt_t *nmt)
807 {
808  assert(boot);
809  assert(net);
810  assert(dev);
811  assert(nmt);
812 
813  int errc = 0;
814 
815  boot->net = net;
816  boot->dev = dev;
817  boot->nmt = nmt;
818 
819  boot->state = NULL;
820 
821  boot->recv = can_recv_create();
822  if (!boot->recv) {
823  errc = get_errc();
824  goto error_create_recv;
825  }
826  can_recv_set_func(boot->recv, &co_nmt_boot_recv, boot);
827 
828  boot->timer = can_timer_create();
829  if (!boot->timer) {
830  errc = get_errc();
831  goto error_create_timer;
832  }
834 
835  boot->id = 0;
836 
837  boot->timeout = 0;
838  boot->sdo = NULL;
839 
840  boot->start = (struct timespec){ 0, 0 };
841  can_net_get_time(boot->net, &boot->start);
842 
843  boot->assignment = 0;
844  boot->ms = 0;
845 
846  boot->st = 0;
847  boot->es = 0;
848 
849  co_sdo_req_init(&boot->req);
850  boot->retry = 0;
851 
853  return boot;
854 
855  // can_timer_destroy(boot->timer);
856 error_create_timer:
857  can_recv_destroy(boot->recv);
858 error_create_recv:
859  set_errc(errc);
860  return NULL;
861 }
862 
863 void
864 __co_nmt_boot_fini(struct __co_nmt_boot *boot)
865 {
866  assert(boot);
867 
868  co_sdo_req_fini(&boot->req);
869 
870  co_csdo_destroy(boot->sdo);
871 
872  can_timer_destroy(boot->timer);
873  can_recv_destroy(boot->recv);
874 }
875 
878 {
879  int errc = 0;
880 
881  co_nmt_boot_t *boot = __co_nmt_boot_alloc();
882  if (!boot) {
883  errc = get_errc();
884  goto error_alloc_boot;
885  }
886 
887  if (!__co_nmt_boot_init(boot, net, dev, nmt)) {
888  errc = get_errc();
889  goto error_init_boot;
890  }
891 
892  return boot;
893 
894 error_init_boot:
895  __co_nmt_boot_free(boot);
896 error_alloc_boot:
897  set_errc(errc);
898  return NULL;
899 }
900 
901 void
903 {
904  if (boot) {
905  __co_nmt_boot_fini(boot);
906  __co_nmt_boot_free(boot);
907  }
908 }
909 
910 int
911 co_nmt_boot_boot_req(co_nmt_boot_t *boot, co_unsigned8_t id, int timeout,
912  co_csdo_ind_t *dn_ind, co_csdo_ind_t *up_ind, void *data)
913 {
914  assert(boot);
915 
916  if (!id || id > CO_NUM_NODES) {
918  return -1;
919  }
920 
921  if (boot->state != co_nmt_boot_wait_state) {
923  return -1;
924  }
925 
926  boot->id = id;
927 
928  boot->timeout = timeout;
929  co_csdo_destroy(boot->sdo);
930  boot->sdo = co_csdo_create(boot->net, NULL, boot->id);
931  if (!boot->sdo)
932  return -1;
933  co_csdo_set_timeout(boot->sdo, boot->timeout);
934  co_csdo_set_dn_ind(boot->sdo, dn_ind, data);
935  co_csdo_set_up_ind(boot->sdo, up_ind, data);
936 
937  co_nmt_boot_emit_time(boot, NULL);
938 
939  return 0;
940 }
941 
942 static int
943 co_nmt_boot_recv(const struct can_msg *msg, void *data)
944 {
945  assert(msg);
946  co_nmt_boot_t *boot = data;
947  assert(boot);
948 
949  co_nmt_boot_emit_recv(boot, msg);
950 
951  return 0;
952 }
953 
954 static int
955 co_nmt_boot_timer(const struct timespec *tp, void *data)
956 {
957  assert(tp);
958  co_nmt_boot_t *boot = data;
959  assert(boot);
960 
961  co_nmt_boot_emit_time(boot, tp);
962 
963  return 0;
964 }
965 
966 static void
967 co_nmt_boot_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
968  co_unsigned32_t ac, void *data)
969 {
970  (void)sdo;
971  (void)idx;
972  (void)subidx;
973  co_nmt_boot_t *boot = data;
974  assert(boot);
975 
976  co_nmt_boot_emit_dn_con(boot, ac);
977 }
978 
979 static void
980 co_nmt_boot_up_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
981  co_unsigned32_t ac, const void *ptr, size_t n, void *data)
982 {
983  (void)sdo;
984  (void)idx;
985  (void)subidx;
986  co_nmt_boot_t *boot = data;
987  assert(boot);
988 
989  co_nmt_boot_emit_up_con(boot, ac, ptr, n);
990 }
991 
992 static void
993 co_nmt_boot_cfg_con(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned32_t ac,
994  void *data)
995 {
996  (void)nmt;
997  (void)id;
998  co_nmt_boot_t *boot = data;
999  assert(boot);
1000 
1001  co_nmt_boot_emit_cfg_con(boot, ac);
1002 }
1003 
1004 static void
1006 {
1007  assert(boot);
1008 
1009  while (next) {
1010  co_nmt_boot_state_t *prev = boot->state;
1011  boot->state = next;
1012 
1013  if (prev && prev->on_leave)
1014  prev->on_leave(boot);
1015 
1016  next = next->on_enter ? next->on_enter(boot) : NULL;
1017  }
1018 }
1019 
1020 static inline void
1022 {
1023  assert(boot);
1024  assert(boot->state);
1025  assert(boot->state->on_recv);
1026 
1027  co_nmt_boot_enter(boot, boot->state->on_recv(boot, msg));
1028 }
1029 
1030 static inline void
1031 co_nmt_boot_emit_time(co_nmt_boot_t *boot, const struct timespec *tp)
1032 {
1033  assert(boot);
1034  assert(boot->state);
1035  assert(boot->state->on_time);
1036 
1037  co_nmt_boot_enter(boot, boot->state->on_time(boot, tp));
1038 }
1039 
1040 static inline void
1041 co_nmt_boot_emit_dn_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
1042 {
1043  assert(boot);
1044  assert(boot->state);
1045  assert(boot->state->on_dn_con);
1046 
1047  co_nmt_boot_enter(boot, boot->state->on_dn_con(boot, ac));
1048 }
1049 
1050 static inline void
1051 co_nmt_boot_emit_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac,
1052  const void *ptr, size_t n)
1053 {
1054  assert(boot);
1055  assert(boot->state);
1056  assert(boot->state->on_up_con);
1057 
1058  co_nmt_boot_enter(boot, boot->state->on_up_con(boot, ac, ptr, n));
1059 }
1060 
1061 static inline void
1062 co_nmt_boot_emit_cfg_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
1063 {
1064  assert(boot);
1065  assert(boot->state);
1066  assert(boot->state->on_cfg_con);
1067 
1068  co_nmt_boot_enter(boot, boot->state->on_cfg_con(boot, ac));
1069 }
1070 
1071 static co_nmt_boot_state_t *
1072 co_nmt_boot_wait_on_time(co_nmt_boot_t *boot, const struct timespec *tp)
1073 {
1074  (void)boot;
1075  (void)tp;
1076 
1077  boot->st = 0;
1078  boot->es = 0;
1079 
1080  // Retrieve the slave assignment for the node.
1081  boot->assignment = co_dev_get_val_u32(boot->dev, 0x1f81, boot->id);
1082 
1083  // Find the consumer heartbeat time for the node.
1084  boot->ms = 0;
1085  co_obj_t *obj_1016 = co_dev_find_obj(boot->dev, 0x1016);
1086  if (obj_1016) {
1087  co_unsigned8_t n = co_obj_get_val_u8(obj_1016, 0x00);
1088  for (size_t i = 1; i <= n; i++) {
1089  co_unsigned32_t val =
1090  co_obj_get_val_u32(obj_1016, i & 0xff);
1091  if (((val >> 16) & 0x7f) == boot->id)
1092  boot->ms = val & 0xffff;
1093  }
1094  }
1095 
1096  // Abort the 'boot slave' process if the slave is not in the network
1097  // list.
1098  if (!(boot->assignment & 0x01)) {
1099  boot->es = 'A';
1100  return co_nmt_boot_abort_state;
1101  }
1102 
1103  if (!(boot->assignment & 0x04))
1104  // Skip booting and start the error control service.
1105  return co_nmt_boot_ec_state;
1106 
1108 }
1109 
1110 static co_nmt_boot_state_t *
1112 {
1113  assert(boot);
1114 
1115  can_recv_stop(boot->recv);
1116  can_timer_stop(boot->timer);
1117 
1118  // If the node is already operational, end the 'boot slave' process with
1119  // error status L.
1120  if (!boot->es && (boot->st & ~CO_NMT_ST_TOGGLE) == CO_NMT_ST_START)
1121  boot->es = 'L';
1122 
1123  // Retry on error status B (see Fig. 4 in CiA 302-2 version 4.1.0).
1124  if (boot->es == 'B') {
1125  int wait = 1;
1126  if (boot->assignment & 0x08) {
1127  // Obtain the time (in milliseconds) the master will
1128  // wait for a mandatory slave to boot.
1129  co_unsigned32_t boot_time = co_dev_get_val_u32(
1130  boot->dev, 0x1f89, 0x00);
1131  // Check if this time has elapsed.
1132  if (boot_time) {
1133  struct timespec now = { 0, 0 };
1134  can_net_get_time(boot->net, &now);
1135  wait = timespec_diff_msec(&now, &boot->start)
1136  < boot_time;
1137  }
1138  }
1139  // If the slave is not mandatory, or the boot time has not yet
1140  // elapsed, wait asynchronously for a while and retry the 'boot
1141  // slave' process.
1142  if (wait) {
1143  can_timer_timeout(boot->timer, boot->net,
1145  return co_nmt_boot_wait_state;
1146  }
1147  }
1148 
1149  return co_nmt_boot_error_state;
1150 }
1151 
1152 static co_nmt_boot_state_t *
1154 {
1155  (void)boot;
1156 
1157  return co_nmt_boot_wait_state;
1158 }
1159 
1160 static void
1162 {
1163  assert(boot);
1164 
1165  co_nmt_boot_con(boot->nmt, boot->id, boot->st, boot->es);
1166 }
1167 
1168 static co_nmt_boot_state_t *
1170 {
1171  assert(boot);
1172 
1173  boot->es = 'B';
1174 
1175  // The device type check may follow an NMT 'reset communication'
1176  // command, in which case we may have to give the slave some time to
1177  // complete the state change. Start the first SDO request by simulating
1178  // a timeout.
1179  boot->retry = LELY_CO_NMT_BOOT_SDO_RETRY + 1;
1181  boot, CO_SDO_AC_TIMEOUT, NULL, 0);
1182 }
1183 
1184 static co_nmt_boot_state_t *
1186  const void *ptr, size_t n)
1187 {
1188  assert(boot);
1189 
1190  // Retry the SDO request on timeout (this includes the first attempt).
1191  if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1192  // Read the device type of the slave (object 1000).
1193  if (co_nmt_boot_up(boot, 0x1000, 0x00) == -1)
1194  return co_nmt_boot_abort_state;
1195  return NULL;
1196  } else if (ac) {
1197  diag(DIAG_ERROR, 0,
1198  "SDO abort code %08" PRIX32
1199  " received on upload request of object 1000 (Device type) to node %02X: %s",
1200  ac, boot->id, co_sdo_ac2str(ac));
1201  return co_nmt_boot_abort_state;
1202  }
1203 
1204  // If the expected device type (sub-object 1F84:ID) is 0, skip the check
1205  // and proceed with the vendor ID.
1206  co_unsigned32_t device_type =
1207  co_dev_get_val_u32(boot->dev, 0x1f84, boot->id);
1208  if (device_type && !co_nmt_boot_chk(boot, 0x1f84, boot->id, ptr, n)) {
1209  boot->es = 'C';
1210  return co_nmt_boot_abort_state;
1211  }
1212 
1213  can_recv_stop(boot->recv);
1215 }
1216 
1217 static co_nmt_boot_state_t *
1219 {
1220  assert(boot);
1221 
1222  // If the expected vendor ID (sub-object 1F85:ID) is 0, skip the check
1223  // and proceed with the product code.
1224  co_unsigned32_t vendor_id =
1225  co_dev_get_val_u32(boot->dev, 0x1f85, boot->id);
1226  if (!vendor_id)
1228 
1229  boot->es = 'D';
1230 
1231  // Read the vendor ID of the slave (sub-object 1018:01).
1232  if (co_nmt_boot_up(boot, 0x1018, 0x01) == -1)
1233  return co_nmt_boot_abort_state;
1234 
1235  return NULL;
1236 }
1237 
1238 static co_nmt_boot_state_t *
1240  const void *ptr, size_t n)
1241 {
1242  assert(boot);
1243 
1244  if (ac)
1245  diag(DIAG_ERROR, 0,
1246  "SDO abort code %08" PRIX32
1247  " received on upload request of sub-object 1018:01 (Vendor-ID) to node %02X: %s",
1248  ac, boot->id, co_sdo_ac2str(ac));
1249 
1250  if (ac || !co_nmt_boot_chk(boot, 0x1f85, boot->id, ptr, n))
1251  return co_nmt_boot_abort_state;
1252 
1254 }
1255 
1256 static co_nmt_boot_state_t *
1258 {
1259  assert(boot);
1260 
1261  // If the expected product code (sub-object 1F86:ID) is 0, skip the
1262  // check and proceed with the revision number.
1263  co_unsigned32_t product_code =
1264  co_dev_get_val_u32(boot->dev, 0x1f86, boot->id);
1265  if (!product_code)
1267 
1268  boot->es = 'M';
1269 
1270  // Read the product code of the slave (sub-object 1018:02).
1271  if (co_nmt_boot_up(boot, 0x1018, 0x02) == -1)
1272  return co_nmt_boot_abort_state;
1273 
1274  return NULL;
1275 }
1276 
1277 static co_nmt_boot_state_t *
1279  const void *ptr, size_t n)
1280 {
1281  assert(boot);
1282 
1283  if (ac)
1284  diag(DIAG_ERROR, 0,
1285  "SDO abort code %08" PRIX32
1286  " received on upload request of sub-object 1018:02 (Product code) to node %02X: %s",
1287  ac, boot->id, co_sdo_ac2str(ac));
1288 
1289  if (ac || !co_nmt_boot_chk(boot, 0x1f86, boot->id, ptr, n))
1290  return co_nmt_boot_abort_state;
1291 
1293 }
1294 
1295 static co_nmt_boot_state_t *
1297 {
1298  assert(boot);
1299 
1300  // If the expected revision number (sub-object 1F87:ID) is 0, skip the
1301  // check and proceed with the serial number.
1302  co_unsigned32_t revision =
1303  co_dev_get_val_u32(boot->dev, 0x1f87, boot->id);
1304  if (!revision)
1306 
1307  boot->es = 'N';
1308 
1309  // Read the revision number of the slave (sub-object 1018:03).
1310  if (co_nmt_boot_up(boot, 0x1018, 0x03) == -1)
1311  return co_nmt_boot_abort_state;
1312 
1313  return NULL;
1314 }
1315 
1316 static co_nmt_boot_state_t *
1318  const void *ptr, size_t n)
1319 {
1320  assert(boot);
1321 
1322  if (ac)
1323  diag(DIAG_ERROR, 0,
1324  "SDO abort code %08" PRIX32
1325  " received on upload request of sub-object 1018:03 (Revision number) to node %02X: %s",
1326  ac, boot->id, co_sdo_ac2str(ac));
1327 
1328  if (ac || !co_nmt_boot_chk(boot, 0x1f87, boot->id, ptr, n))
1329  return co_nmt_boot_abort_state;
1330 
1332 }
1333 
1334 static co_nmt_boot_state_t *
1336 {
1337  assert(boot);
1338 
1339  // If the expected serial number (sub-object 1F88:ID) is 0, skip the
1340  // check and proceed to 'check node state'.
1341  co_unsigned32_t serial_nr =
1342  co_dev_get_val_u32(boot->dev, 0x1f88, boot->id);
1343  if (!serial_nr)
1345 
1346  boot->es = 'O';
1347 
1348  // Read the serial number of the slave (sub-object 1018:04).
1349  if (co_nmt_boot_up(boot, 0x1018, 0x04) == -1)
1350  return co_nmt_boot_abort_state;
1351 
1352  return NULL;
1353 }
1354 
1355 static co_nmt_boot_state_t *
1357  const void *ptr, size_t n)
1358 {
1359  assert(boot);
1360 
1361  if (ac)
1362  diag(DIAG_ERROR, 0,
1363  "SDO abort code %08" PRIX32
1364  " received on upload request of sub-object 1018:04 (Serial number) to node %02X: %s",
1365  ac, boot->id, co_sdo_ac2str(ac));
1366 
1367  if (ac || !co_nmt_boot_chk(boot, 0x1f88, boot->id, ptr, n))
1368  return co_nmt_boot_abort_state;
1369 
1371 }
1372 
1373 static co_nmt_boot_state_t *
1375 {
1376  assert(boot);
1377 
1378  // If the keep-alive bit is set, check the node state.
1379  if (boot->assignment & 0x10) {
1380  int ms;
1381  if (boot->ms) {
1382  ms = boot->ms;
1383  boot->es = 'E';
1384  } else {
1386  boot->es = 'F';
1387  // If we're not a heartbeat consumer, start node
1388  // guarding by sending the first RTR.
1389  co_nmt_boot_send_rtr(boot);
1390  }
1391 
1392  // Start the CAN frame receiver for the heartbeat or node guard
1393  // message.
1394  can_recv_start(boot->recv, boot->net, CO_NMT_EC_CANID(boot->id),
1395  0);
1396  // Start the CAN timer in case we do not receive a heartbeat
1397  // indication or a node guard confirmation.
1398  can_timer_timeout(boot->timer, boot->net, ms);
1399 
1400  return NULL;
1401  }
1402 
1403  return co_nmt_boot_chk_sw_state;
1404 }
1405 
1406 static co_nmt_boot_state_t *
1408 {
1409  assert(boot);
1410  assert(msg);
1411  assert(msg->id == (uint_least32_t)CO_NMT_EC_CANID(boot->id));
1412 
1413  can_timer_stop(boot->timer);
1414 
1415  if (msg->len >= 1) {
1416  boot->st = msg->data[0];
1417  if ((boot->st & ~CO_NMT_ST_TOGGLE) == CO_NMT_ST_START)
1418  // If the node is already operational, skip the 'check
1419  // and update software version' and 'check
1420  // configuration' steps and proceed immediately to
1421  // 'start error control service'.
1422  return co_nmt_boot_ec_state;
1423  }
1424  boot->st = 0;
1425  // If the node is not operational, send the NMT 'reset
1426  // communication' command and proceed as if the keep-alive bit
1427  // was not set.
1428  co_nmt_cs_req(boot->nmt, CO_NMT_CS_RESET_COMM, boot->id);
1430 }
1431 
1432 static co_nmt_boot_state_t *
1433 co_nmt_boot_chk_node_on_time(co_nmt_boot_t *boot, const struct timespec *tp)
1434 {
1435  (void)boot;
1436  (void)tp;
1437 
1438  return co_nmt_boot_abort_state;
1439 }
1440 
1441 static void
1443 {
1444  assert(boot);
1445 
1446  can_recv_stop(boot->recv);
1447 }
1448 
1449 static co_nmt_boot_state_t *
1451 {
1452  assert(boot);
1453 
1454  // Start the CAN frame receiver for the boot-up message.
1455  can_recv_start(boot->recv, boot->net, CO_NMT_EC_CANID(boot->id), 0);
1456  // Wait until we receive a boot-up message.
1458  boot->timer, boot->net, LELY_CO_NMT_BOOT_RESET_TIMEOUT);
1459 
1460  return NULL;
1461 }
1462 
1463 static co_nmt_boot_state_t *
1465 {
1466  (void)boot;
1467  (void)msg;
1468 
1469  can_recv_stop(boot->recv);
1470  return co_nmt_boot_chk_sw_state;
1471 }
1472 
1473 static co_nmt_boot_state_t *
1474 co_nmt_boot_reset_comm_on_time(co_nmt_boot_t *boot, const struct timespec *tp)
1475 {
1476  (void)boot;
1477  (void)tp;
1478 
1479  return co_nmt_boot_abort_state;
1480 }
1481 
1482 static co_nmt_boot_state_t *
1484 {
1485  assert(boot);
1486 
1487  if (boot->assignment & 0x20) {
1488  boot->es = 'G';
1489 
1490  // Abort if the expected program software identification
1491  // (sub-object 1F55:ID) is 0.
1492  co_unsigned32_t sw_id =
1493  co_dev_get_val_u32(boot->dev, 0x1f55, boot->id);
1494  if (!sw_id)
1495  return co_nmt_boot_abort_state;
1496 
1497  // The software version check may follow an NMT 'reset
1498  // communication' command, in which case we may have to give the
1499  // slave some time to complete the state change. Start the first
1500  // SDO request by simulating a timeout.
1501  boot->retry = LELY_CO_NMT_BOOT_SDO_RETRY + 1;
1503  boot, CO_SDO_AC_TIMEOUT, NULL, 0);
1504  }
1505 
1506  // Continue with the 'check configuration' step if the software version
1507  // check is not necessary.
1509 }
1510 
1511 static co_nmt_boot_state_t *
1513  const void *ptr, size_t n)
1514 {
1515  assert(boot);
1516 
1517  // Retry the SDO request on timeout (this includes the first attempt).
1518  if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1519  // Read the program software identification of the slave
1520  // (sub-object 1F56:01).
1521  if (co_nmt_boot_up(boot, 0x1f56, 0x01) == -1)
1522  return co_nmt_boot_abort_state;
1523  return NULL;
1524  } else if (ac) {
1525  diag(DIAG_ERROR, 0,
1526  "SDO abort code %08" PRIX32
1527  " received on upload request of sub-object 1F56:01 (Program software identification) to node %02X: %s",
1528  ac, boot->id, co_sdo_ac2str(ac));
1529  return co_nmt_boot_abort_state;
1530  }
1531 
1532  // If the program software identification matches the expected value,
1533  // proceed to 'check configuration'.
1534  if (co_nmt_boot_chk(boot, 0x1f55, boot->id, ptr, n))
1536 
1537  // Do not update the software if software update (bit 6) is not allowed
1538  // or if the keep-alive bit (bit 4) is set.
1539  if ((boot->assignment & 0x50) != 0x40) {
1540  boot->es = 'H';
1541  return co_nmt_boot_abort_state;
1542  }
1543 
1544  boot->es = 'I';
1545 
1547 }
1548 
1549 static co_nmt_boot_state_t *
1551 {
1552  assert(boot);
1553 
1554  // Read the program control of the slave (sub-object 1F51:01).
1555  if (co_nmt_boot_up(boot, 0x1f51, 0x01) == -1)
1556  return co_nmt_boot_abort_state;
1557 
1558  return NULL;
1559 }
1560 
1561 static co_nmt_boot_state_t *
1563 {
1564  assert(boot);
1565 
1566  // The download SDO request may be unconfirmed on some devices since it
1567  // stops the program on the slave (and may cause a restart of the
1568  // bootloader). We therefore ignore timeouts.
1569  if (ac && ac != CO_SDO_AC_TIMEOUT) {
1570  diag(DIAG_ERROR, 0,
1571  "SDO abort code %08" PRIX32
1572  " received on download request of sub-object 1F51:01 (Program control) to node %02X: %s",
1573  ac, boot->id, co_sdo_ac2str(ac));
1574  return co_nmt_boot_abort_state;
1575  }
1576 
1578 }
1579 
1580 static co_nmt_boot_state_t *
1582  const void *ptr, size_t n)
1583 {
1584  assert(boot);
1585 
1586  // If the value is already 0 (Program stopped), do not write a 0 (Stop
1587  // program), but skip to the 'clear program' state.
1588  co_unsigned8_t val = 0;
1589  // clang-format off
1590  if (!ac && co_val_read(CO_DEFTYPE_UNSIGNED8, &val, ptr,
1591  (const uint_least8_t *)ptr + n) && !val)
1592  // clang-format on
1594 
1595  // Write a 0 (Stop program) to the program control of the slave
1596  // (sub-object 1F51:01).
1597  // clang-format off
1598  if (co_nmt_boot_dn(boot, 0x1f51, 0x01, CO_DEFTYPE_UNSIGNED8,
1599  &(co_unsigned8_t){ 0 }) == -1)
1600  // clang-format on
1601  return co_nmt_boot_abort_state;
1602 
1603  return NULL;
1604 }
1605 
1606 static co_nmt_boot_state_t *
1608 {
1609  assert(boot);
1610 
1611  // The 'clear program' command follows the 'stop program' command, which
1612  // may have triggered a reboot of the slave. In that case we may have to
1613  // give the slave some time to finish booting. Start the first SDO
1614  // request by simulating a timeout.
1615  boot->retry = LELY_CO_NMT_BOOT_SDO_RETRY + 1;
1617 }
1618 
1619 static co_nmt_boot_state_t *
1621 {
1622  assert(boot);
1623 
1624  // Retry the SDO request on timeout.
1625  if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1626  // Write a 3 (Clear program) to the program control of the slave
1627  // (sub-object 1F51:01).
1628  // clang-format off
1629  if (co_nmt_boot_dn(boot, 0x1f51, 0x01, CO_DEFTYPE_UNSIGNED8,
1630  &(co_unsigned8_t){ 3 }) == -1)
1631  // clang-format on
1632  return co_nmt_boot_abort_state;
1633  return NULL;
1634  } else if (ac) {
1635  diag(DIAG_ERROR, 0,
1636  "SDO abort code %08" PRIX32
1637  " received on download request of sub-object 1F51:01 (Program control) to node %02X: %s",
1638  ac, boot->id, co_sdo_ac2str(ac));
1639  return co_nmt_boot_abort_state;
1640  }
1641 
1643 }
1644 
1645 static co_nmt_boot_state_t *
1647 {
1648  assert(boot);
1649 
1650  co_sub_t *sub = co_dev_find_sub(boot->dev, 0x1f58, boot->id);
1651  if (!sub)
1652  return co_nmt_boot_abort_state;
1653 
1654  // Upload the program data.
1655  struct co_sdo_req *req = &boot->req;
1656  co_sdo_req_clear(req);
1657  co_unsigned32_t ac = co_sub_up_ind(sub, req);
1658  if (ac || !co_sdo_req_first(req) || !co_sdo_req_last(req)) {
1659  if (ac)
1660  diag(DIAG_ERROR, 0,
1661  "SDO abort code %08" PRIX32
1662  " on upload request of object 1F58:%02X (Program data): %s",
1663  ac, boot->id, co_sdo_ac2str(ac));
1664  return co_nmt_boot_abort_state;
1665  }
1666 
1667  // The 'clear program' step may take some time to complete, causing an
1668  // immediate 'download program' to generate a timeout. Start the first
1669  // attempt by simulating a timeout.
1670  boot->retry = LELY_CO_NMT_BOOT_SDO_RETRY + 1;
1672 }
1673 
1674 static co_nmt_boot_state_t *
1676 {
1677  (void)boot;
1678 
1679  // Retry the SDO request on timeout (this includes the first attempt).
1680  if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1681  struct co_sdo_req *req = &boot->req;
1682  // Write the program data (sub-object 1F58:ID) to the program
1683  // data of the slave (sub-object 1F50:01) using SDO block
1684  // transfer.
1685  // clang-format off
1686  if (co_csdo_blk_dn_req(boot->sdo, 0x1f50, 0x01, req->buf,
1687  req->size, &co_nmt_boot_dn_con, boot) == -1)
1688  // clang-format on
1689  return co_nmt_boot_abort_state;
1690  return NULL;
1691  } else if (ac) {
1692  // If SDO block transfer is not supported, fall back to SDO
1693  // segmented transfer.
1695  }
1696 
1698 }
1699 
1700 static co_nmt_boot_state_t *
1702 {
1703  assert(boot);
1704 
1705  // If SDO block transfer is not supported, we may still have to wait for
1706  // the 'clear program' step to complete before successfully doing a
1707  // segmented SDO transfer. Start the first attempt by simulating a
1708  // timeout.
1709  boot->retry = LELY_CO_NMT_BOOT_SDO_RETRY + 1;
1711 }
1712 
1713 static co_nmt_boot_state_t *
1715 {
1716  assert(boot);
1717 
1718  // Retry the SDO request on timeout (this includes the first attempt).
1719  if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1720  struct co_sdo_req *req = &boot->req;
1721  // Write the program data (sub-object 1F58:ID) to the program
1722  // data of the slave (sub-object 1F50:01) using SDO segmented
1723  // transfer.
1724  // clang-format off
1725  if (co_csdo_dn_req(boot->sdo, 0x1f50, 0x01, req->buf, req->size,
1726  &co_nmt_boot_dn_con, boot) == -1)
1727  // clang-format on
1728  return co_nmt_boot_abort_state;
1729  return NULL;
1730  } else if (ac) {
1731  diag(DIAG_ERROR, 0,
1732  "SDO abort code %08" PRIX32
1733  " received on download request of sub-object 1F50:01 (Program data) to node %02X: %s",
1734  ac, boot->id, co_sdo_ac2str(ac));
1735  return co_nmt_boot_abort_state;
1736  }
1737 
1739 }
1740 
1741 static co_nmt_boot_state_t *
1743 {
1744  assert(boot);
1745 
1746  // Wait for a while before checking the flash status indication.
1748  boot->timer, boot->net, LELY_CO_NMT_BOOT_CHECK_TIMEOUT);
1749 
1750  return NULL;
1751 }
1752 
1753 static co_nmt_boot_state_t *
1754 co_nmt_boot_wait_flash_on_time(co_nmt_boot_t *boot, const struct timespec *tp)
1755 {
1756  assert(boot);
1757  (void)tp;
1758 
1759  // Read the flash status indication of the slave (sub-object 1F57:01).
1760  if (co_nmt_boot_up(boot, 0x1f57, 0x01) == -1)
1761  return co_nmt_boot_abort_state;
1762 
1763  return NULL;
1764 }
1765 
1766 static co_nmt_boot_state_t *
1768  const void *ptr, size_t n)
1769 {
1770  assert(boot);
1771 
1772  if (ac)
1773  diag(DIAG_ERROR, 0,
1774  "SDO abort code %08" PRIX32
1775  " received on upload request of sub-object 1F57:01 (Flash status indication) to node %02X: %s",
1776  ac, boot->id, co_sdo_ac2str(ac));
1777 
1778  // If the flash status indication is not valid, try again.
1779  co_unsigned32_t val = 0;
1780  // clang-format off
1781  if (!co_val_read(CO_DEFTYPE_UNSIGNED32, &val, ptr,
1782  (const uint_least8_t *)ptr + n) || (val & 0x01))
1783  // clang-format on
1785 
1786  co_unsigned8_t st = (val >> 1) & 0x7f;
1787  switch (st) {
1788  case 0: return co_nmt_boot_chk_prog_state;
1789  case 1:
1790  diag(DIAG_ERROR, 0,
1791  "flash status identification %d: No valid program available",
1792  st);
1793  break;
1794  case 2:
1795  diag(DIAG_ERROR, 0,
1796  "flash status identification %d: Data format unknown",
1797  st);
1798  break;
1799  case 3:
1800  diag(DIAG_ERROR, 0,
1801  "flash status identification %d: Data format error or data CRC error",
1802  st);
1803  break;
1804  case 4:
1805  diag(DIAG_ERROR, 0,
1806  "flash status identification %d: Flash not cleared before write",
1807  st);
1808  break;
1809  case 5:
1810  diag(DIAG_ERROR, 0,
1811  "flash status identification %d: Flash write error",
1812  st);
1813  break;
1814  case 6:
1815  diag(DIAG_ERROR, 0,
1816  "flash status identification %d: General address error",
1817  st);
1818  break;
1819  case 7:
1820  diag(DIAG_ERROR, 0,
1821  "flash status identification %d: Flash secured (= write access currently forbidden)",
1822  st);
1823  break;
1824  case 63:
1825  diag(DIAG_ERROR, 0,
1826  "flash status identification %d: Unspecified error",
1827  st);
1828  break;
1829  default:
1830  if (st > 63)
1831  diag(DIAG_ERROR, 0,
1832  "flash status identification %d: Manufacturer-specific error: 0x%08" PRIX32
1833  "",
1834  st, (val >> 16) & 0xffff);
1835  break;
1836  }
1837 
1838  return co_nmt_boot_abort_state;
1839 }
1840 
1841 static co_nmt_boot_state_t *
1843 {
1844  assert(boot);
1845 
1846  // Read the program software identification of the slave (sub-object
1847  // 1F56:01).
1848  if (co_nmt_boot_up(boot, 0x1f56, 0x01) == -1)
1849  return co_nmt_boot_abort_state;
1850 
1851  return NULL;
1852 }
1853 
1854 static co_nmt_boot_state_t *
1856  const void *ptr, size_t n)
1857 {
1858  assert(boot);
1859 
1860  if (ac)
1861  diag(DIAG_ERROR, 0,
1862  "SDO abort code %08" PRIX32
1863  " received on upload request of sub-object 1F56:01 (Program software identification) to node %02X: %s",
1864  ac, boot->id, co_sdo_ac2str(ac));
1865 
1866  if (ac || !co_nmt_boot_chk(boot, 0x1f55, boot->id, ptr, n))
1867  return co_nmt_boot_abort_state;
1868 
1870 }
1871 
1872 static co_nmt_boot_state_t *
1874 {
1875  assert(boot);
1876 
1877  // Write a 1 (Start program) to the program control of the slave
1878  // (sub-object 1F51:01).
1879  // clang-format off
1880  if (co_nmt_boot_dn(boot, 0x1f51, 0x01, CO_DEFTYPE_UNSIGNED8,
1881  &(co_unsigned8_t){ 1 }) == -1)
1882  // clang-format on
1883  return co_nmt_boot_abort_state;
1884 
1885  return NULL;
1886 }
1887 
1888 static co_nmt_boot_state_t *
1890 {
1891  assert(boot);
1892 
1893  if (ac) {
1894  diag(DIAG_ERROR, 0,
1895  "SDO abort code %08" PRIX32
1896  " received on download request of sub-object 1F51:01 (Program control) to node %02X: %s",
1897  ac, boot->id, co_sdo_ac2str(ac));
1898  return co_nmt_boot_abort_state;
1899  }
1900 
1902 }
1903 
1904 static co_nmt_boot_state_t *
1906 {
1907  assert(boot);
1908 
1909  // Wait for a while before checking the program control.
1911  boot->timer, boot->net, LELY_CO_NMT_BOOT_CHECK_TIMEOUT);
1912 
1913  return NULL;
1914 }
1915 
1916 static co_nmt_boot_state_t *
1917 co_nmt_boot_wait_prog_on_time(co_nmt_boot_t *boot, const struct timespec *tp)
1918 {
1919  assert(boot);
1920  (void)tp;
1921 
1922  // The 'start program' step may take some time to complete, causing an
1923  // immediate SDO upload request to generate a timeout. Start the first
1924  // attempt by simulating a timeout.
1925  boot->retry = LELY_CO_NMT_BOOT_SDO_RETRY + 1;
1927  boot, CO_SDO_AC_TIMEOUT, NULL, 0);
1928 
1929  return NULL;
1930 }
1931 
1932 static co_nmt_boot_state_t *
1934  const void *ptr, size_t n)
1935 {
1936  assert(boot);
1937 
1938  // Retry the SDO request on timeout (this includes the first attempt).
1939  if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1940  // Read the program control of the slave (sub-object 1F51:01).
1941  if (co_nmt_boot_up(boot, 0x1f51, 0x01) == -1)
1942  return co_nmt_boot_abort_state;
1943  return NULL;
1944  } else if (ac) {
1945  diag(DIAG_ERROR, 0,
1946  "SDO abort code %08" PRIX32
1947  " received on upload request of sub-object 1F51:01 (Program control) to node %02X: %s",
1948  ac, boot->id, co_sdo_ac2str(ac));
1949  return co_nmt_boot_abort_state;
1950  }
1951 
1952  // If the program control differs from 'Program started', try again.
1953  co_unsigned8_t val = 0;
1954  // clang-format off
1955  if (!co_val_read(CO_DEFTYPE_UNSIGNED8, &val, ptr,
1956  (const uint_least8_t *)ptr + n) || val != 1)
1957  // clang-format on
1959 
1961 }
1962 
1963 static co_nmt_boot_state_t *
1965 {
1966  assert(boot);
1967 
1968  boot->es = 'J';
1969 
1970  // If the expected configuration date (sub-object 1F26:ID) or time
1971  // (sub-object 1F27:ID) are not configured, proceed to 'update
1972  // configuration'.
1973  co_unsigned32_t cfg_date =
1974  co_dev_get_val_u32(boot->dev, 0x1f26, boot->id);
1975  co_unsigned32_t cfg_time =
1976  co_dev_get_val_u32(boot->dev, 0x1f27, boot->id);
1977  if (!cfg_date || !cfg_time)
1978  return co_nmt_boot_up_cfg_state;
1979 
1980  // The configuration check may follow an NMT 'reset communication'
1981  // command (if the 'check software version' step was skipped), in which
1982  // case we may have to give the slave some time to complete the state
1983  // change. Start the first SDO request by simulating a timeout.
1984  boot->retry = LELY_CO_NMT_BOOT_SDO_RETRY + 1;
1986  boot, CO_SDO_AC_TIMEOUT, NULL, 0);
1987 }
1988 
1989 static co_nmt_boot_state_t *
1991  const void *ptr, size_t n)
1992 {
1993  assert(boot);
1994 
1995  // Retry the SDO request on timeout (this includes the first attempt).
1996  if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1997  // Read the configuration date of the slave (sub-object
1998  // 1020:01).
1999  if (co_nmt_boot_up(boot, 0x1020, 0x01) == -1)
2000  return co_nmt_boot_abort_state;
2001  return NULL;
2002  } else if (ac) {
2003  diag(DIAG_ERROR, 0,
2004  "SDO abort code %08" PRIX32
2005  " received on upload request of sub-object 1020:01 (Configuration date) to node %02X: %s",
2006  ac, boot->id, co_sdo_ac2str(ac));
2007  }
2008 
2009  // If the configuration date does not match the expected value, skip
2010  // checking the time and proceed to 'update configuration'.
2011  if (ac || !co_nmt_boot_chk(boot, 0x1f26, boot->id, ptr, n))
2012  return co_nmt_boot_up_cfg_state;
2013 
2014  // Read the configuration time of the slave (sub-object 1020:02).
2015  if (co_nmt_boot_up(boot, 0x1020, 0x02) == -1)
2016  return co_nmt_boot_abort_state;
2017 
2019 }
2020 
2021 static co_nmt_boot_state_t *
2023  const void *ptr, size_t n)
2024 {
2025  assert(boot);
2026 
2027  if (ac)
2028  diag(DIAG_ERROR, 0,
2029  "SDO abort code %08" PRIX32
2030  " received on upload request of sub-object 1020:02 (Configuration time) to node %02X: %s",
2031  ac, boot->id, co_sdo_ac2str(ac));
2032 
2033  // If the configuration time does not match the expected value, proceed
2034  // to 'update configuration'.
2035  if (ac || !co_nmt_boot_chk(boot, 0x1f27, boot->id, ptr, n))
2036  return co_nmt_boot_up_cfg_state;
2037 
2038  return co_nmt_boot_ec_state;
2039 }
2040 
2041 static co_nmt_boot_state_t *
2043 {
2044  assert(boot);
2045 
2046  boot->es = 'J';
2047 
2048  // clang-format off
2049  if (co_nmt_cfg_req(boot->nmt, boot->id, boot->timeout,
2050  &co_nmt_boot_cfg_con, boot) == -1)
2051  // clang-format on
2052  return co_nmt_boot_abort_state;
2053 
2054  return NULL;
2055 }
2056 
2057 static co_nmt_boot_state_t *
2059 {
2060  assert(boot);
2061 
2062  if (ac) {
2063  diag(DIAG_ERROR, 0,
2064  "SDO abort code %08" PRIX32
2065  " received while updating the configuration of node %02X: %s",
2066  ac, boot->id, co_sdo_ac2str(ac));
2067  return co_nmt_boot_abort_state;
2068  }
2069 
2070  return co_nmt_boot_ec_state;
2071 }
2072 
2073 static co_nmt_boot_state_t *
2075 {
2076  assert(boot);
2077 
2078  if (boot->ms) {
2079  boot->es = 'K';
2080  // Start the CAN frame receiver for heartbeat messages.
2081  can_recv_start(boot->recv, boot->net, CO_NMT_EC_CANID(boot->id),
2082  0);
2083  // Wait for the first heartbeat indication.
2084  can_timer_timeout(boot->timer, boot->net, boot->ms);
2085  return NULL;
2086  } else if (boot->assignment & 0x01) {
2087  // If the guard time is non-zero, start node guarding by sending
2088  // the first RTR, but do not wait for the response.
2089  co_unsigned16_t gt = (boot->assignment >> 16) & 0xffff;
2090  if (gt)
2091  co_nmt_boot_send_rtr(boot);
2092  }
2093 
2094  boot->es = 0;
2095  return co_nmt_boot_abort_state;
2096 }
2097 
2098 static co_nmt_boot_state_t *
2100 {
2101  assert(boot);
2102  assert(msg);
2103  assert(msg->id == (uint_least32_t)CO_NMT_EC_CANID(boot->id));
2104 
2105  if (msg->len >= 1) {
2106  co_unsigned8_t st = msg->data[0];
2107  // Do not consider a boot-up message to be a heartbeat message.
2108  if (st == CO_NMT_ST_BOOTUP)
2109  return NULL;
2110  boot->st = st;
2111  boot->es = 0;
2112  }
2113 
2114  return co_nmt_boot_abort_state;
2115 }
2116 
2117 static co_nmt_boot_state_t *
2118 co_nmt_boot_ec_on_time(co_nmt_boot_t *boot, const struct timespec *tp)
2119 {
2120  (void)boot;
2121  (void)tp;
2122 
2123  return co_nmt_boot_abort_state;
2124 }
2125 
2126 static int
2127 co_nmt_boot_dn(co_nmt_boot_t *boot, co_unsigned16_t idx, co_unsigned8_t subidx,
2128  co_unsigned16_t type, const void *val)
2129 {
2130  assert(boot);
2131 
2132  return co_csdo_dn_val_req(boot->sdo, idx, subidx, type, val,
2133  &co_nmt_boot_dn_con, boot);
2134 }
2135 
2136 static int
2137 co_nmt_boot_up(co_nmt_boot_t *boot, co_unsigned16_t idx, co_unsigned8_t subidx)
2138 {
2139  assert(boot);
2140 
2141  return co_csdo_up_req(
2142  boot->sdo, idx, subidx, &co_nmt_boot_up_con, boot);
2143 }
2144 
2145 static int
2146 co_nmt_boot_chk(co_nmt_boot_t *boot, co_unsigned16_t idx, co_unsigned8_t subidx,
2147  const void *ptr, size_t n)
2148 {
2149  assert(boot);
2150 
2151  co_sub_t *sub = co_dev_find_sub(boot->dev, idx, subidx);
2152  if (!sub)
2153  return 0;
2154  co_unsigned16_t type = co_sub_get_type(sub);
2155 
2156  union co_val val;
2157  if (!co_val_read(type, &val, ptr, (const uint_least8_t *)ptr + n))
2158  return 0;
2159 
2160  int eq = !co_val_cmp(type, &val, co_sub_get_val(sub));
2161  co_val_fini(type, &val);
2162  return eq;
2163 }
2164 
2165 static int
2167 {
2168  assert(boot);
2169 
2170  struct can_msg msg = CAN_MSG_INIT;
2171  msg.id = CO_NMT_EC_CANID(boot->id);
2172  msg.flags |= CAN_FLAG_RTR;
2173 
2174  return can_net_send(boot->net, &msg);
2175 }
2176 
2177 #endif // !LELY_NO_CO_MASTER
co_nmt_boot_dn_prog_on_dn_con
static co_nmt_boot_state_t * co_nmt_boot_dn_prog_on_dn_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
The 'SDO download confirmation' transition function of the 'download program' state.
Definition: nmt_boot.c:1714
CO_SDO_AC_TIMEOUT
#define CO_SDO_AC_TIMEOUT
SDO abort code: SDO protocol timed out.
Definition: sdo.h:66
can_recv_destroy
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition: net.c:562
co_nmt_boot_chk_prog_on_enter
static co_nmt_boot_state_t * co_nmt_boot_chk_prog_on_enter(co_nmt_boot_t *boot)
The entry function of the 'check program SW ID state.
Definition: nmt_boot.c:1842
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:481
co_nmt_boot_blk_dn_prog_state
static co_nmt_boot_state_t *const co_nmt_boot_blk_dn_prog_state
The 'download program' state (see Fig. 3 in CiA 302-3 version 4.1.0).
Definition: nmt_boot.c:542
co_nmt_boot_chk_revision_on_enter
static co_nmt_boot_state_t * co_nmt_boot_chk_revision_on_enter(co_nmt_boot_t *boot)
The entry function of the 'check revision number' state.
Definition: nmt_boot.c:1296
LELY_CO_NMT_BOOT_RTR_TIMEOUT
#define LELY_CO_NMT_BOOT_RTR_TIMEOUT
The timeout (in milliseconds) after sending a node guarding RTR.
Definition: nmt_boot.c:51
__co_nmt_boot::assignment
co_unsigned32_t assignment
The NMT slave assignment (object 1F81).
Definition: nmt_boot.c:97
co_nmt_boot_dn_prog_on_enter
static co_nmt_boot_state_t * co_nmt_boot_dn_prog_on_enter(co_nmt_boot_t *boot)
The entry function of the 'download program' state.
Definition: nmt_boot.c:1701
co_nmt_cfg_req
int co_nmt_cfg_req(co_nmt_t *nmt, co_unsigned8_t id, int timeout, co_nmt_cfg_con_t *con, void *data)
Issues the NMT 'configuration request' for the specified node.
Definition: nmt.c:1701
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_nmt_boot_blk_dn_prog_on_dn_con
static co_nmt_boot_state_t * co_nmt_boot_blk_dn_prog_on_dn_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
The 'SDO download confirmation' transition function of the 'download program' state.
Definition: nmt_boot.c:1675
dev.h
co_nmt_boot_emit_cfg_con
static void co_nmt_boot_emit_cfg_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
Invokes the 'configuration request confirmation' transition function of the current state of a 'boot ...
Definition: nmt_boot.c:1062
can_net_get_time
void can_net_get_time(const can_net_t *net, struct timespec *tp)
Retrieves the current time of a CAN network interface.
Definition: net.c:204
co_sub_get_val
const void * co_sub_get_val(const co_sub_t *sub)
Returns a pointer to the current value of a CANopen sub-object.
Definition: obj.c:679
__co_nmt_boot::sdo
co_csdo_t * sdo
A pointer to the Client-SDO used to access slave objects.
Definition: nmt_boot.c:93
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
co_nmt_boot_chk_device_type_state
static co_nmt_boot_state_t *const co_nmt_boot_chk_device_type_state
The 'check device type' state (see Fig. 5 in CiA 302-2 version 4.1.0).
Definition: nmt_boot.c:330
val.h
co_val_fini
void co_val_fini(co_unsigned16_t type, void *val)
Finalizes a value of the specified data type.
Definition: val.c:275
CO_DEFTYPE_UNSIGNED32
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50
co_nmt_boot_abort_on_enter
static co_nmt_boot_state_t * co_nmt_boot_abort_on_enter(co_nmt_boot_t *boot)
The entry function of the 'abort' state.
Definition: nmt_boot.c:1111
co_nmt_boot_error_on_enter
static co_nmt_boot_state_t * co_nmt_boot_error_on_enter(co_nmt_boot_t *boot)
The entry function of the 'error' state.
Definition: nmt_boot.c:1153
co_nmt_boot_chk_product_code_on_enter
static co_nmt_boot_state_t * co_nmt_boot_chk_product_code_on_enter(co_nmt_boot_t *boot)
The entry function of the 'check product code' state.
Definition: nmt_boot.c:1257
co_nmt_boot_emit_time
static void co_nmt_boot_emit_time(co_nmt_boot_t *boot, const struct timespec *tp)
Invokes the 'timeout' transition function of the current state of a 'boot slave' service.
Definition: nmt_boot.c:1031
co_nmt_boot_chk_node_on_time
static co_nmt_boot_state_t * co_nmt_boot_chk_node_on_time(co_nmt_boot_t *boot, const struct timespec *tp)
The 'timeout' transition function of the 'check node state' state.
Definition: nmt_boot.c:1433
LELY_CO_NMT_BOOT_SDO_RETRY
#define LELY_CO_NMT_BOOT_SDO_RETRY
The number of times an SDO request is retried after a timeout.
Definition: nmt_boot.c:46
can_msg
A CAN or CAN FD format frame.
Definition: msg.h:87
co_nmt_boot_up_cfg_state
static co_nmt_boot_state_t *const co_nmt_boot_up_cfg_state
The 'update configuration' state (see Fig.
Definition: nmt_boot.c:710
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_nmt_boot_reset_comm_on_recv
static co_nmt_boot_state_t * co_nmt_boot_reset_comm_on_recv(co_nmt_boot_t *boot, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'reset communication' state.
Definition: nmt_boot.c:1464
diag.h
co_nmt_boot_reset_comm_state
static co_nmt_boot_state_t *const co_nmt_boot_reset_comm_state
The 'reset communication' state (see Fig. 6 in CiA 302-2 version 4.1.0).
Definition: nmt_boot.c:460
co_nmt_boot_start_prog_on_enter
static co_nmt_boot_state_t * co_nmt_boot_start_prog_on_enter(co_nmt_boot_t *boot)
The entry function of the 'start program' state.
Definition: nmt_boot.c:1873
can_timer_set_func
void can_timer_set_func(can_timer_t *timer, can_timer_func_t *func, void *data)
Sets the callback function invoked when a CAN timer is triggered.
Definition: net.c:428
can_timer_stop
void can_timer_stop(can_timer_t *timer)
Stops a CAN timer and unregisters it with a network interface.
Definition: net.c:468
co_nmt_boot_start_prog_on_dn_con
static co_nmt_boot_state_t * co_nmt_boot_start_prog_on_dn_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
The 'SDO download confirmation' transition function of the 'start program' state.
Definition: nmt_boot.c:1889
__can_recv
A CAN frame receiver.
Definition: net.c:99
co_sdo_ac2str
const char * co_sdo_ac2str(co_unsigned32_t ac)
Returns a string describing an SDO abort code.
Definition: sdo.c:57
co_nmt_boot_stop_prog_on_enter
static co_nmt_boot_state_t * co_nmt_boot_stop_prog_on_enter(co_nmt_boot_t *boot)
The entry function of the 'stop program' state.
Definition: nmt_boot.c:1550
nmt_boot.h
co_nmt_boot_dn_con
static void co_nmt_boot_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac, void *data)
The CANopen SDO download confirmation callback function for a 'boot slave' service.
Definition: nmt_boot.c:967
LELY_CO_NMT_BOOT_WAIT_TIMEOUT
#define LELY_CO_NMT_BOOT_WAIT_TIMEOUT
The timeout (in milliseconds) before trying to boot the slave again.
Definition: nmt_boot.c:41
can_recv_set_func
void can_recv_set_func(can_recv_t *recv, can_recv_func_t *func, void *data)
Sets the callback function used to process CAN frames with a receiver.
Definition: net.c:582
co_nmt_boot_error_on_leave
static void co_nmt_boot_error_on_leave(co_nmt_boot_t *boot)
The exit function of the 'error' state.
Definition: nmt_boot.c:1161
co_nmt_boot_timer
static int co_nmt_boot_timer(const struct timespec *tp, void *data)
The CAN timer callback function for a 'boot slave' service.
Definition: nmt_boot.c:955
get_errc
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
co_nmt_boot_boot_req
int co_nmt_boot_boot_req(co_nmt_boot_t *boot, co_unsigned8_t id, int timeout, co_csdo_ind_t *dn_ind, co_csdo_ind_t *up_ind, void *data)
Starts a CANopen NMT 'boot slave' service.
Definition: nmt_boot.c:911
co_nmt_boot_clear_prog_on_enter
static co_nmt_boot_state_t * co_nmt_boot_clear_prog_on_enter(co_nmt_boot_t *boot)
The entry function of the 'clear program' state.
Definition: nmt_boot.c:1607
co_nmt_boot_create
co_nmt_boot_t * co_nmt_boot_create(can_net_t *net, co_dev_t *dev, co_nmt_t *nmt)
Creates a new CANopen NMT 'boot slave' service.
Definition: nmt_boot.c:877
__co_nmt_boot_state::on_recv
co_nmt_boot_state_t *(* on_recv)(co_nmt_boot_t *boot, const struct can_msg *msg)
A pointer to the transition function invoked when a CAN frame has been received.
Definition: nmt_boot.c:223
__co_nmt_boot::recv
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: nmt_boot.c:85
errno2c
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
co_nmt_boot_stop_prog_on_up_con
static co_nmt_boot_state_t * co_nmt_boot_stop_prog_on_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
The 'SDO upload confirmation' transition function of the 'stop program' state.
Definition: nmt_boot.c:1581
co_nmt_boot_recv
static int co_nmt_boot_recv(const struct can_msg *msg, void *data)
The CAN receive callback function for a 'boot slave' service.
Definition: nmt_boot.c:943
co_nmt_boot_emit_dn_con
static void co_nmt_boot_emit_dn_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
Invokes the 'SDO download confirmation' transition function of the current state of a 'boot slave' se...
Definition: nmt_boot.c:1041
CO_DEFTYPE_UNSIGNED8
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition: type.h:44
__co_nmt_boot_state::on_leave
void(* on_leave)(co_nmt_boot_t *boot)
A pointer to the function invoked when the current state is left.
Definition: nmt_boot.c:271
co.h
co_nmt_cs_req
int co_nmt_cs_req(co_nmt_t *nmt, co_unsigned8_t cs, co_unsigned8_t id)
Submits an NMT request to a slave.
Definition: nmt.c:1569
CO_NMT_EC_CANID
#define CO_NMT_EC_CANID(id)
The CAN identifier used for both node guarding and heartbeat monitoring.
Definition: nmt.h:76
co_nmt_boot_chk_node_on_recv
static co_nmt_boot_state_t * co_nmt_boot_chk_node_on_recv(co_nmt_boot_t *boot, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'check node state' state.
Definition: nmt_boot.c:1407
co_nmt_boot_chk_sw_state
static co_nmt_boot_state_t *const co_nmt_boot_chk_sw_state
The 'check software' state (see Fig. 6 in CiA 302-2 version 4.1.0).
Definition: nmt_boot.c:478
__co_nmt_boot::retry
int retry
The number of SDO retries remaining.
Definition: nmt_boot.c:103
co_nmt_boot_abort_state
static co_nmt_boot_state_t *const co_nmt_boot_abort_state
The 'abort' state.
Definition: nmt_boot.c:296
LELY_CO_NMT_BOOT_CHECK_TIMEOUT
#define LELY_CO_NMT_BOOT_CHECK_TIMEOUT
The timeout (in milliseconds) before checking the flash status indication or the program control of a...
Definition: nmt_boot.c:67
co_nmt_boot_wait_flash_on_up_con
static co_nmt_boot_state_t * co_nmt_boot_wait_flash_on_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
The 'SDO upload confirmation' transition function of the 'wait for end of flashing' state.
Definition: nmt_boot.c:1767
CAN_MSG_INIT
#define CAN_MSG_INIT
The static initializer for can_msg.
Definition: msg.h:113
co_nmt_boot_chk_vendor_id_on_up_con
static co_nmt_boot_state_t * co_nmt_boot_chk_vendor_id_on_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
The 'SDO upload confirmation' transition function of the 'check vendor ID' state.
Definition: nmt_boot.c:1239
co_nmt_boot_stop_prog_state
static co_nmt_boot_state_t *const co_nmt_boot_stop_prog_state
The 'stop program' state (see Fig. 3 in CiA 302-3 version 4.1.0).
Definition: nmt_boot.c:504
__co_nmt_boot_state::on_cfg_con
co_nmt_boot_state_t *(* on_cfg_con)(co_nmt_boot_t *boot, co_unsigned32_t ac)
A pointer to the transition function invoked when an NMT 'configuration request' completes.
Definition: nmt_boot.c:268
__co_nmt_boot::state
co_nmt_boot_state_t * state
A pointer to the current state.
Definition: nmt_boot.c:83
co_nmt_boot_up_cfg_on_cfg_con
static co_nmt_boot_state_t * co_nmt_boot_up_cfg_on_cfg_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
The 'configuration request confirmation' transition unction of the 'update configuration' state.
Definition: nmt_boot.c:2058
co_nmt_boot_reset_comm_on_time
static co_nmt_boot_state_t * co_nmt_boot_reset_comm_on_time(co_nmt_boot_t *boot, const struct timespec *tp)
The 'timeout' transition function of the 'reset communication' state.
Definition: nmt_boot.c:1474
co_nmt_boot_chk_sw_on_up_con
static co_nmt_boot_state_t * co_nmt_boot_chk_sw_on_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
The 'SDO upload confirmation' transition function of the 'check software' state.
Definition: nmt_boot.c:1512
__co_nmt_boot_state::on_time
co_nmt_boot_state_t *(* on_time)(co_nmt_boot_t *boot, const struct timespec *tp)
A pointer to the transition function invoked when a timeout occurs.
Definition: nmt_boot.c:233
co_nmt_boot_ec_on_enter
static co_nmt_boot_state_t * co_nmt_boot_ec_on_enter(co_nmt_boot_t *boot)
The entry function of the 'start error control' state.
Definition: nmt_boot.c:2074
co_nmt_boot_emit_up_con
static void co_nmt_boot_emit_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
Invokes the 'SDO upload confirmation' transition function of the current state of a 'boot slave' serv...
Definition: nmt_boot.c:1051
DIAG_ERROR
@ DIAG_ERROR
An error.
Definition: diag.h:49
__co_nmt_boot::st
co_unsigned8_t st
The state of the node (including the toggle bit).
Definition: nmt_boot.c:105
co_nmt_boot_wait_flash_on_time
static co_nmt_boot_state_t * co_nmt_boot_wait_flash_on_time(co_nmt_boot_t *boot, const struct timespec *tp)
The 'timeout' transition function of the 'wait for end of flashing' state.
Definition: nmt_boot.c:1754
co_nmt_boot_up
static int co_nmt_boot_up(co_nmt_boot_t *boot, co_unsigned16_t idx, co_unsigned8_t subidx)
Issues an SDO upload request to the slave.
Definition: nmt_boot.c:2137
__can_timer
A CAN timer.
Definition: net.c:63
co_nmt_boot_chk_serial_nr_on_enter
static co_nmt_boot_state_t * co_nmt_boot_chk_serial_nr_on_enter(co_nmt_boot_t *boot)
The entry function of the 'check serial number' state.
Definition: nmt_boot.c:1335
__co_nmt_boot::req
struct co_sdo_req req
The CANopen SDO upload request used for reading sub-objects.
Definition: nmt_boot.c:101
co_nmt_boot_ec_on_recv
static co_nmt_boot_state_t * co_nmt_boot_ec_on_recv(co_nmt_boot_t *boot, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'start error control' state.
Definition: nmt_boot.c:2099
set_errnum
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
co_nmt_boot_chk_prog_on_up_con
static co_nmt_boot_state_t * co_nmt_boot_chk_prog_on_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
The 'SDO upload confirmation' transition function of the 'check program SW ID' state.
Definition: nmt_boot.c:1855
set_errc
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
__co_nmt_boot::start
struct timespec start
The time at which the 'boot slave' request was received.
Definition: nmt_boot.c:95
co_nmt_boot_chk_node_on_enter
static co_nmt_boot_state_t * co_nmt_boot_chk_node_on_enter(co_nmt_boot_t *boot)
The entry function of the 'check node state' state.
Definition: nmt_boot.c:1374
can_timer_destroy
void can_timer_destroy(can_timer_t *timer)
Destroys a CAN timer.
Definition: net.c:407
LELY_CO_NMT_BOOT_RESET_TIMEOUT
#define LELY_CO_NMT_BOOT_RESET_TIMEOUT
The timeout (in milliseconds) after sending the NMT 'reset communication' command.
Definition: nmt_boot.c:59
co_nmt_boot_blk_dn_prog_on_enter
static co_nmt_boot_state_t * co_nmt_boot_blk_dn_prog_on_enter(co_nmt_boot_t *boot)
The entry function of the 'download program' state.
Definition: nmt_boot.c:1646
__co_nmt_boot::dev
co_dev_t * dev
A pointer to a CANopen device.
Definition: nmt_boot.c:79
__co_nmt_boot_state::on_enter
co_nmt_boot_state_t *(* on_enter)(co_nmt_boot_t *boot)
A pointer to the function invoked when a new state is entered.
Definition: nmt_boot.c:213
co_sdo_req
A CANopen SDO upload/download request.
Definition: sdo.h:178
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_NMT_ST_TOGGLE
#define CO_NMT_ST_TOGGLE
The mask to get/set the toggle bit from an NMT state.
Definition: nmt.h:73
co_csdo_create
co_csdo_t * co_csdo_create(can_net_t *net, co_dev_t *dev, co_unsigned8_t num)
Creates a new CANopen Client-SDO service.
Definition: csdo.c:868
co_nmt_boot_chk_vendor_id_on_enter
static co_nmt_boot_state_t * co_nmt_boot_chk_vendor_id_on_enter(co_nmt_boot_t *boot)
The entry function of the 'check vendor ID' state.
Definition: nmt_boot.c:1218
__co_nmt_boot_state::on_dn_con
co_nmt_boot_state_t *(* on_dn_con)(co_nmt_boot_t *boot, co_unsigned32_t ac)
A pointer to the transition function invoked when an SDO download request completes.
Definition: nmt_boot.c:244
co_nmt_boot_wait_flash_on_enter
static co_nmt_boot_state_t * co_nmt_boot_wait_flash_on_enter(co_nmt_boot_t *boot)
The entry function of the 'wait for end of flashing' state.
Definition: nmt_boot.c:1742
CO_NMT_ST_BOOTUP
#define CO_NMT_ST_BOOTUP
The NMT state 'boot-up'.
Definition: nmt.h:55
co_nmt_boot_cfg_con
static void co_nmt_boot_cfg_con(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned32_t ac, void *data)
The CANopen NMT 'configuration request' confirmation callback function for a 'boot slave' service.
Definition: nmt_boot.c:993
co_nmt_boot_chk_cfg_date_state
static co_nmt_boot_state_t *const co_nmt_boot_chk_cfg_date_state
The 'check configuration date' state (see Fig.
Definition: nmt_boot.c:673
co_csdo_destroy
void co_csdo_destroy(co_csdo_t *sdo)
Destroys a CANopen Client-SDO service.
Definition: csdo.c:895
ERRNUM_INVAL
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:129
co_sdo_req_init
void co_sdo_req_init(struct co_sdo_req *req)
Initializes a CANopen SDO upload/download request.
Definition: sdo.c:109
co_sdo_req_first
int co_sdo_req_first(const struct co_sdo_req *req)
Returns 1 if the specified request includes the first segment, and 0 otherwise.
Definition: sdo.h:340
co_nmt_boot_wait_on_time
static co_nmt_boot_state_t * co_nmt_boot_wait_on_time(co_nmt_boot_t *boot, const struct timespec *tp)
The 'timeout' transition function of the 'wait asynchronously' state.
Definition: nmt_boot.c:1072
co_nmt_boot_chk_serial_nr_state
static co_nmt_boot_state_t *const co_nmt_boot_chk_serial_nr_state
The 'check serial number' state (see Fig. 5 in CiA 302-2 version 4.1.0).
Definition: nmt_boot.c:410
co_nmt_boot_chk_revision_state
static co_nmt_boot_state_t *const co_nmt_boot_chk_revision_state
The 'check revision number' state (see Fig. 5 in CiA 302-2 version 4.1.0).
Definition: nmt_boot.c:390
co_sdo_req::size
size_t size
The total size (in bytes) of the value to be uploaded/downloaded.
Definition: sdo.h:184
__co_nmt
A CANopen NMT master/slave service.
Definition: nmt.c:104
co_nmt_boot_chk_sw_on_enter
static co_nmt_boot_state_t * co_nmt_boot_chk_sw_on_enter(co_nmt_boot_t *boot)
The entry function of the 'check software' state.
Definition: nmt_boot.c:1483
__co_nmt_boot::timer
can_timer_t * timer
A pointer to the CAN timer.
Definition: nmt_boot.c:87
ERRNUM_INPROGRESS
@ ERRNUM_INPROGRESS
Operation in progress.
Definition: errnum.h:125
co_nmt_boot_chk_prog_state
static co_nmt_boot_state_t *const co_nmt_boot_chk_prog_state
The 'check program SW ID' state (see Fig. 8 in CiA 302-2 version 4.1.0).
Definition: nmt_boot.c:603
co_nmt_boot_chk_product_code_on_up_con
static co_nmt_boot_state_t * co_nmt_boot_chk_product_code_on_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
The 'SDO upload confirmation' transition function of the 'check product code' state.
Definition: nmt_boot.c:1278
time.h
co_nmt_boot_chk_vendor_id_state
static co_nmt_boot_state_t *const co_nmt_boot_chk_vendor_id_state
The 'check vendor ID' state (see Fig. 5 in CiA 302-2 version 4.1.0).
Definition: nmt_boot.c:350
__co_nmt_boot::net
can_net_t * net
A pointer to a CAN network interface.
Definition: nmt_boot.c:77
__co_nmt_boot::id
co_unsigned8_t id
The node-ID.
Definition: nmt_boot.c:89
__co_nmt_boot
A CANopen NMT 'boot slave' service.
Definition: nmt_boot.c:75
co_nmt_boot_chk_cfg_date_on_up_con
static co_nmt_boot_state_t * co_nmt_boot_chk_cfg_date_on_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
The 'SDO upload confirmation' transition function of the 'check configuration date' state.
Definition: nmt_boot.c:1990
co_val_cmp
int co_val_cmp(co_unsigned16_t type, const void *v1, const void *v2)
Compares two values of the specified data type.
Definition: val.c:397
co_nmt_boot_emit_recv
static void co_nmt_boot_emit_recv(co_nmt_boot_t *boot, const struct can_msg *msg)
Invokes the 'CAN frame received' transition function of the current state of a 'boot slave' service.
Definition: nmt_boot.c:1021
co_val
A union of the CANopen static data types.
Definition: val.h:163
diag
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
co_sdo_req_last
int co_sdo_req_last(const struct co_sdo_req *req)
Returns 1 if the specified request includes the last segment, and 0 otherwise.
Definition: sdo.h:346
can_recv_start
void can_recv_start(can_recv_t *recv, can_net_t *net, uint_least32_t id, uint_least8_t flags)
Registers a CAN frame receiver with a network interface and starts processing frames.
Definition: net.c:591
co_nmt_boot_clear_prog_state
static co_nmt_boot_state_t *const co_nmt_boot_clear_prog_state
The 'clear program' state (see Fig. 3 in CiA 302-3 version 4.1.0).
Definition: nmt_boot.c:523
__co_obj
A CANopen object.
Definition: obj.h:32
co_csdo_blk_dn_req
int co_csdo_blk_dn_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
Submits a block download request to a remote Server-SDO.
Definition: csdo.c:1098
co_nmt_boot_reset_comm_on_enter
static co_nmt_boot_state_t * co_nmt_boot_reset_comm_on_enter(co_nmt_boot_t *boot)
The entry function of the 'reset communication' state.
Definition: nmt_boot.c:1450
co_nmt_boot_ec_state
static co_nmt_boot_state_t *const co_nmt_boot_ec_state
The 'start error control' state (see Fig. 11 in CiA 302-2 version 4.1.0).
Definition: nmt_boot.c:733
co_nmt_boot_up_cfg_on_enter
static co_nmt_boot_state_t * co_nmt_boot_up_cfg_on_enter(co_nmt_boot_t *boot)
The entry function of the 'update configuration' state.
Definition: nmt_boot.c:2042
co_nmt_boot_dn_prog_state
static co_nmt_boot_state_t *const co_nmt_boot_dn_prog_state
The 'download program' state (see Fig. 3 in CiA 302-3 version 4.1.0).
Definition: nmt_boot.c:560
CAN_FLAG_RTR
@ CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames).
Definition: msg.h:48
co_nmt_boot_chk_serial_nr_on_up_con
static co_nmt_boot_state_t * co_nmt_boot_chk_serial_nr_on_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
The 'SDO upload confirmation' transition function of the 'check serial number' state.
Definition: nmt_boot.c:1356
__co_dev
A CANopen device.
Definition: dev.c:41
co_csdo_up_req
int co_csdo_up_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_csdo_up_con_t *con, void *data)
Submits an upload request to a remote Server-SDO.
Definition: csdo.c:1079
co_nmt_boot_wait_flash_state
static co_nmt_boot_state_t *const co_nmt_boot_wait_flash_state
The 'check flashing' state (see Fig. 3 in CiA 302-3 version 4.1.0).
Definition: nmt_boot.c:585
can_net_send
int can_net_send(can_net_t *net, const struct can_msg *msg)
Sends a CAN frame from a network interface.
Definition: net.c:308
__co_nmt_boot::es
char es
The error status.
Definition: nmt_boot.c:107
co_nmt_boot_chk_product_code_state
static co_nmt_boot_state_t *const co_nmt_boot_chk_product_code_state
The 'check product code' state (see Fig. 5 in CiA 302-2 version 4.1.0).
Definition: nmt_boot.c:370
co_nmt_boot_clear_prog_on_dn_con
static co_nmt_boot_state_t * co_nmt_boot_clear_prog_on_dn_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
The 'SDO download confirmation' transition function of the 'clear program' state.
Definition: nmt_boot.c:1620
__co_nmt_boot::timeout
int timeout
The SDO timeout (in milliseconds).
Definition: nmt_boot.c:91
co_csdo_set_timeout
void co_csdo_set_timeout(co_csdo_t *sdo, int timeout)
Sets the timeout of a Client-SDO.
Definition: csdo.c:945
co_sdo_req::buf
const void * buf
A pointer to the next bytes to be uploaded/downloaded.
Definition: sdo.h:186
co_nmt_boot_destroy
void co_nmt_boot_destroy(co_nmt_boot_t *boot)
Destroys a CANopen NMT 'boot slave' service.
Definition: nmt_boot.c:902
co_nmt_boot_dn
static int co_nmt_boot_dn(co_nmt_boot_t *boot, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned16_t type, const void *val)
Issues an SDO download request to the slave.
Definition: nmt_boot.c:2127
co_nmt_boot_chk
static int co_nmt_boot_chk(co_nmt_boot_t *boot, co_unsigned16_t idx, co_unsigned8_t subidx, const void *ptr, size_t n)
Compares the result of an SDO upload request to the value of a local sub-object.
Definition: nmt_boot.c:2146
co_nmt_boot_enter
static void co_nmt_boot_enter(co_nmt_boot_t *boot, co_nmt_boot_state_t *next)
Enters the specified state of a 'boot slave' service and invokes the exit and entry functions.
Definition: nmt_boot.c:1005
timespec_diff_msec
int_least64_t timespec_diff_msec(const struct timespec *t1, const struct timespec *t2)
Returns the time difference (in milliseconds) between *t1 and *t2.
Definition: time.h:207
__co_csdo
A CANopen Client-SDO.
Definition: csdo.c:45
co_nmt_boot_wait_prog_on_up_con
static co_nmt_boot_state_t * co_nmt_boot_wait_prog_on_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
The 'SDO upload confirmation' transition function of the 'wait till program is started' state.
Definition: nmt_boot.c:1933
co_nmt_boot_chk_cfg_time_on_up_con
static co_nmt_boot_state_t * co_nmt_boot_chk_cfg_time_on_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
The 'SDO upload confirmation' transition function of the 'check configuration time' state.
Definition: nmt_boot.c:2022
co_nmt_boot_wait_prog_state
static co_nmt_boot_state_t *const co_nmt_boot_wait_prog_state
The 'wait till program is started' state (see Fig.
Definition: nmt_boot.c:651
co_nmt_boot_chk_cfg_date_on_enter
static co_nmt_boot_state_t * co_nmt_boot_chk_cfg_date_on_enter(co_nmt_boot_t *boot)
The entry function of the 'check configuration date' state.
Definition: nmt_boot.c:1964
co_nmt_boot_send_rtr
static int co_nmt_boot_send_rtr(co_nmt_boot_t *boot)
Sends a node guarding RTR to the slave.
Definition: nmt_boot.c:2166
co_nmt_boot_stop_prog_on_dn_con
static co_nmt_boot_state_t * co_nmt_boot_stop_prog_on_dn_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
The 'SDO download confirmation' transition function of the 'stop program' state.
Definition: nmt_boot.c:1562
co_nmt_boot_error_state
static co_nmt_boot_state_t *const co_nmt_boot_error_state
The 'error' state.
Definition: nmt_boot.c:310
co_nmt_boot_chk_cfg_time_state
static co_nmt_boot_state_t *const co_nmt_boot_chk_cfg_time_state
The 'check configuration time' state (see Fig.
Definition: nmt_boot.c:690
co_nmt_boot_wait_prog_on_time
static co_nmt_boot_state_t * co_nmt_boot_wait_prog_on_time(co_nmt_boot_t *boot, const struct timespec *tp)
The 'timeout' transition function of the 'wait till program is started' state.
Definition: nmt_boot.c:1917
CO_NMT_CS_RESET_COMM
#define CO_NMT_CS_RESET_COMM
The NMT command specifier 'reset communication'.
Definition: nmt.h:52
co_sub_up_ind
co_unsigned32_t co_sub_up_ind(const co_sub_t *sub, struct co_sdo_req *req)
Invokes the upload indication function of a CANopen sub-object, registered with co_sub_set_up_ind().
Definition: obj.c:1019
__co_nmt_boot_state::on_up_con
co_nmt_boot_state_t *(* on_up_con)(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
A pointer to the transition function invoked when an SDO upload request completes.
Definition: nmt_boot.c:257
co_csdo_set_up_ind
void co_csdo_set_up_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO upload reques...
Definition: csdo.c:987
co_csdo_dn_req
int co_csdo_dn_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
Submits a download request to a remote Server-SDO.
Definition: csdo.c:1012
co_sdo_req_fini
void co_sdo_req_fini(struct co_sdo_req *req)
Finalizes a CANopen SDO upload/download request.
Definition: sdo.c:121
CO_NMT_ST_START
#define CO_NMT_ST_START
The NMT state 'operational'.
Definition: nmt.h:61
stdlib.h
co_nmt_boot_wait_prog_on_enter
static co_nmt_boot_state_t * co_nmt_boot_wait_prog_on_enter(co_nmt_boot_t *boot)
The entry function of the 'wait till program is started' state.
Definition: nmt_boot.c:1905
co_nmt_boot_up_con
static void co_nmt_boot_up_con(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 CANopen SDO upload confirmation callback function for a 'boot slave' service.
Definition: nmt_boot.c:980
__co_sub
A CANopen sub-object.
Definition: obj.h:54
co_nmt_boot_chk_device_type_on_enter
static co_nmt_boot_state_t * co_nmt_boot_chk_device_type_on_enter(co_nmt_boot_t *boot)
The entry function of the 'check device type' state.
Definition: nmt_boot.c:1169
co_dev_find_sub
co_sub_t * co_dev_find_sub(const co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx)
Finds a sub-object in the object dictionary of a CANopen device.
Definition: dev.c:299
__co_nmt_boot::ms
co_unsigned16_t ms
The consumer heartbeat time (in milliseconds).
Definition: nmt_boot.c:99
co_nmt_boot_con
void co_nmt_boot_con(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, char es)
The CANopen NMT 'boot slave' confirmation function, invoked when the 'boot slave' process completes.
Definition: nmt.c:1977
co_nmt_boot_chk_revision_on_up_con
static co_nmt_boot_state_t * co_nmt_boot_chk_revision_on_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
The 'SDO upload confirmation' transition function of the 'check revision number' state.
Definition: nmt_boot.c:1317
co_csdo_set_dn_ind
void co_csdo_set_dn_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO download requ...
Definition: csdo.c:967
co_nmt_boot_chk_node_on_leave
static void co_nmt_boot_chk_node_on_leave(co_nmt_boot_t *boot)
The exit function of the 'check node state' state.
Definition: nmt_boot.c:1442
co_sub_get_type
co_unsigned16_t co_sub_get_type(const co_sub_t *sub)
Returns the data type of a CANopen sub-object.
Definition: obj.c:570
co_nmt_boot_wait_state
static co_nmt_boot_state_t *const co_nmt_boot_wait_state
The 'wait asynchronously' state.
Definition: nmt_boot.c:286
co_nmt_boot_start_prog_state
static co_nmt_boot_state_t *const co_nmt_boot_start_prog_state
The 'start program' state (see Fig. 3 in CiA 302-3 version 4.1.0).
Definition: nmt_boot.c:622
co_csdo_dn_val_req
int co_csdo_dn_val_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned16_t type, const void *val, co_csdo_dn_con_t *con, void *data)
Submits a download request to a remote Server-SDO.
Definition: csdo.c:1034
__co_nmt_boot_state
A CANopen NMT 'boot slave' state.
Definition: nmt_boot.c:211
obj.h
can_recv_stop
void can_recv_stop(can_recv_t *recv)
Stops a CAN frame receiver from processing frames and unregisters it with the network interface.
Definition: net.c:613
__can_net
A CAN network interface.
Definition: net.c:37
can_recv_create
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition: net.c:537
can_timer_create
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition: net.c:382
can_timer_timeout
void can_timer_timeout(can_timer_t *timer, can_net_t *net, int timeout)
Starts a CAN timer and registers it with a network interface.
Definition: net.c:484
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_nmt_boot_ec_on_time
static co_nmt_boot_state_t * co_nmt_boot_ec_on_time(co_nmt_boot_t *boot, const struct timespec *tp)
The 'timeout' transition function of the 'start error control' state.
Definition: nmt_boot.c:2118
co_nmt_boot_chk_node_state
static co_nmt_boot_state_t *const co_nmt_boot_chk_node_state
The 'check node state' state (see Fig. 6 in CiA 302-2 version 4.1.0).
Definition: nmt_boot.c:436
__co_nmt_boot::nmt
co_nmt_t * nmt
A pointer to an NMT master service.
Definition: nmt_boot.c:81
co_nmt_boot_chk_device_type_on_up_con
static co_nmt_boot_state_t * co_nmt_boot_chk_device_type_on_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr, size_t n)
The 'SDO upload confirmation' transition function of the 'check device type' state.
Definition: nmt_boot.c:1185
co_dev_find_obj
co_obj_t * co_dev_find_obj(const co_dev_t *dev, co_unsigned16_t idx)
Finds an object in the object dictionary of a CANopen device.
Definition: dev.c:288