Lely core libraries 2.3.4
nmt_boot.c
Go to the documentation of this file.
1
24#include "co.h"
25
26#if !LELY_NO_CO_MASTER && !LELY_NO_CO_NMT_BOOT
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#if !LELY_NO_STDIO
37#include <inttypes.h>
38#endif
39#include <stdlib.h>
40
41#ifndef LELY_CO_NMT_BOOT_WAIT_TIMEOUT
43#define LELY_CO_NMT_BOOT_WAIT_TIMEOUT 1000
44#endif
45
46#ifndef LELY_CO_NMT_BOOT_SDO_RETRY
48#define LELY_CO_NMT_BOOT_SDO_RETRY 3
49#endif
50
51#if !LELY_NO_CO_NG
52#ifndef LELY_CO_NMT_BOOT_RTR_TIMEOUT
54#define LELY_CO_NMT_BOOT_RTR_TIMEOUT 100
55#endif
56#endif
57
58#ifndef LELY_CO_NMT_BOOT_RESET_TIMEOUT
63#define LELY_CO_NMT_BOOT_RESET_TIMEOUT 1000
64#endif
65
66#ifndef LELY_CO_NMT_BOOT_CHECK_TIMEOUT
71#define LELY_CO_NMT_BOOT_CHECK_TIMEOUT 100
72#endif
73
77
93 co_unsigned8_t id;
101 co_unsigned32_t assignment;
103 co_unsigned16_t ms;
107 int retry;
109 co_unsigned8_t st;
111 char es;
112};
113
119static int co_nmt_boot_recv(const struct can_msg *msg, void *data);
120
126static int co_nmt_boot_timer(const struct timespec *tp, void *data);
127
134static void co_nmt_boot_dn_con(co_csdo_t *sdo, co_unsigned16_t idx,
135 co_unsigned8_t subidx, co_unsigned32_t ac, void *data);
136
143static void co_nmt_boot_up_con(co_csdo_t *sdo, co_unsigned16_t idx,
144 co_unsigned8_t subidx, co_unsigned32_t ac, const void *ptr,
145 size_t n, void *data);
146
153static void co_nmt_boot_cfg_con(co_nmt_t *nmt, co_unsigned8_t id,
154 co_unsigned32_t ac, void *data);
155
160static void co_nmt_boot_enter(co_nmt_boot_t *boot, co_nmt_boot_state_t *next);
161
169static inline void co_nmt_boot_emit_recv(
170 co_nmt_boot_t *boot, const struct can_msg *msg);
171
179static inline void co_nmt_boot_emit_time(
180 co_nmt_boot_t *boot, const struct timespec *tp);
181
189static inline void co_nmt_boot_emit_dn_con(
190 co_nmt_boot_t *boot, co_unsigned32_t ac);
191
201static inline void co_nmt_boot_emit_up_con(co_nmt_boot_t *boot,
202 co_unsigned32_t ac, const void *ptr, size_t n);
203
211static inline void co_nmt_boot_emit_cfg_con(
212 co_nmt_boot_t *boot, co_unsigned32_t ac);
213
228 co_nmt_boot_t *boot, const struct can_msg *msg);
238 co_nmt_boot_t *boot, const struct timespec *tp);
248 co_nmt_boot_state_t *(*on_dn_con)(
249 co_nmt_boot_t *boot, co_unsigned32_t ac);
262 co_unsigned32_t ac, const void *ptr, size_t n);
272 co_nmt_boot_state_t *(*on_cfg_con)(
273 co_nmt_boot_t *boot, co_unsigned32_t ac);
275 void (*on_leave)(co_nmt_boot_t *boot);
276};
277
278#define LELY_CO_DEFINE_STATE(name, ...) \
279 static co_nmt_boot_state_t *const name = \
280 &(co_nmt_boot_state_t){ __VA_ARGS__ };
281
284 co_nmt_boot_t *boot, const struct timespec *tp);
285
287// clang-format off
288LELY_CO_DEFINE_STATE(co_nmt_boot_wait_state,
289 .on_time = &co_nmt_boot_wait_on_time
291// clang-format on
292
293
295
297// clang-format off
298LELY_CO_DEFINE_STATE(co_nmt_boot_abort_state,
299 .on_enter = &co_nmt_boot_abort_on_enter
301// clang-format on
302
305
308
310// clang-format off
311LELY_CO_DEFINE_STATE(co_nmt_boot_error_state,
312 .on_enter = &co_nmt_boot_error_on_enter,
313 .on_leave = &co_nmt_boot_error_on_leave
315// clang-format on
316
319 co_nmt_boot_t *boot);
320
326 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
327 size_t n);
328
330// clang-format off
331LELY_CO_DEFINE_STATE(co_nmt_boot_chk_device_type_state,
335// clang-format on
336
339 co_nmt_boot_t *boot);
340
346 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
347 size_t n);
348
350// clang-format off
351LELY_CO_DEFINE_STATE(co_nmt_boot_chk_vendor_id_state,
355// clang-format on
356
359 co_nmt_boot_t *boot);
360
366 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
367 size_t n);
368
370// clang-format off
371LELY_CO_DEFINE_STATE(co_nmt_boot_chk_product_code_state,
375// clang-format on
376
379 co_nmt_boot_t *boot);
380
386 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
387 size_t n);
388
390// clang-format off
391LELY_CO_DEFINE_STATE(co_nmt_boot_chk_revision_state,
395// clang-format on
396
399 co_nmt_boot_t *boot);
400
406 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
407 size_t n);
408
410// clang-format off
411LELY_CO_DEFINE_STATE(co_nmt_boot_chk_serial_nr_state,
415// clang-format on
416
419
424 co_nmt_boot_t *boot, const struct can_msg *msg);
425
428 co_nmt_boot_t *boot, const struct timespec *tp);
429
432
434// clang-format off
435LELY_CO_DEFINE_STATE(co_nmt_boot_chk_node_state,
441// clang-format on
442
445 co_nmt_boot_t *boot);
446
452 co_nmt_boot_t *boot, const struct can_msg *msg);
453
456 co_nmt_boot_t *boot, const struct timespec *tp);
457
459// clang-format off
460LELY_CO_DEFINE_STATE(co_nmt_boot_reset_comm_state,
465// clang-format on
466
469
475 co_unsigned32_t ac, const void *ptr, size_t n);
476
478// clang-format off
479LELY_CO_DEFINE_STATE(co_nmt_boot_chk_sw_state,
480 .on_enter = &co_nmt_boot_chk_sw_on_enter,
481 .on_up_con = &co_nmt_boot_chk_sw_on_up_con
483// clang-format on
484
487
493 co_nmt_boot_t *boot, co_unsigned32_t ac);
494
500 co_unsigned32_t ac, const void *ptr, size_t n);
501
503// clang-format off
504LELY_CO_DEFINE_STATE(co_nmt_boot_stop_prog_state,
509// clang-format on
510
513 co_nmt_boot_t *boot);
514
520 co_nmt_boot_t *boot, co_unsigned32_t ac);
521
523// clang-format off
524LELY_CO_DEFINE_STATE(co_nmt_boot_clear_prog_state,
528// clang-format on
529
532 co_nmt_boot_t *boot);
533
539 co_nmt_boot_t *boot, co_unsigned32_t ac);
540
542// clang-format off
543LELY_CO_DEFINE_STATE(co_nmt_boot_blk_dn_prog_state,
547// clang-format on
548
551
557 co_nmt_boot_t *boot, co_unsigned32_t ac);
558
560// clang-format off
561LELY_CO_DEFINE_STATE(co_nmt_boot_dn_prog_state,
562 .on_enter = &co_nmt_boot_dn_prog_on_enter,
565// clang-format on
566
569 co_nmt_boot_t *boot);
570
573 co_nmt_boot_t *boot, const struct timespec *tp);
574
580 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
581 size_t n);
582
584// clang-format off
585LELY_CO_DEFINE_STATE(co_nmt_boot_wait_flash_state,
590// clang-format on
591
594
600 co_unsigned32_t ac, const void *ptr, size_t n);
601
603// clang-format off
604LELY_CO_DEFINE_STATE(co_nmt_boot_chk_prog_state,
608// clang-format on
609
612 co_nmt_boot_t *boot);
613
619 co_nmt_boot_t *boot, co_unsigned32_t ac);
620
622// clang-format off
623LELY_CO_DEFINE_STATE(co_nmt_boot_start_prog_state,
627// clang-format on
628
631
637 co_nmt_boot_t *boot, const struct timespec *tp);
638
644 co_unsigned32_t ac, const void *ptr, size_t n);
645
650// clang-format off
651LELY_CO_DEFINE_STATE(co_nmt_boot_wait_prog_state,
656// clang-format on
657
660 co_nmt_boot_t *boot);
661
667 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
668 size_t n);
669
673// clang-format off
674LELY_CO_DEFINE_STATE(co_nmt_boot_chk_cfg_date_state,
678// clang-format on
679
685 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
686 size_t n);
687
691// clang-format off
692LELY_CO_DEFINE_STATE(co_nmt_boot_chk_cfg_time_state,
695// clang-format on
696
699
705 co_nmt_boot_t *boot, co_unsigned32_t ac);
706
710// clang-format off
711LELY_CO_DEFINE_STATE(co_nmt_boot_up_cfg_state,
712 .on_enter = &co_nmt_boot_up_cfg_on_enter,
713 .on_cfg_con = &co_nmt_boot_up_cfg_on_cfg_con
715// clang-format on
716
719
725 co_nmt_boot_t *boot, const struct can_msg *msg);
726
729 co_nmt_boot_t *boot, const struct timespec *tp);
730
732// clang-format off
733LELY_CO_DEFINE_STATE(co_nmt_boot_ec_state,
734 .on_enter = &co_nmt_boot_ec_on_enter,
735 .on_recv = &co_nmt_boot_ec_on_recv,
736 .on_time = &co_nmt_boot_ec_on_time
738// clang-format on
739
740#undef LELY_CO_DEFINE_STATE
741
754static int co_nmt_boot_dn(co_nmt_boot_t *boot, co_unsigned16_t idx,
755 co_unsigned8_t subidx, co_unsigned16_t type, const void *val);
756
767static int co_nmt_boot_up(co_nmt_boot_t *boot, co_unsigned16_t idx,
768 co_unsigned8_t subidx);
769
783static int co_nmt_boot_chk(co_nmt_boot_t *boot, co_unsigned16_t idx,
784 co_unsigned8_t subidx, const void *ptr, size_t n);
785
786#if !LELY_NO_CO_NG
792static int co_nmt_boot_send_rtr(co_nmt_boot_t *boot);
793#endif
794
795void *
796__co_nmt_boot_alloc(void)
797{
798 void *ptr = malloc(sizeof(struct __co_nmt_boot));
799#if !LELY_NO_ERRNO
800 if (!ptr)
801 set_errc(errno2c(errno));
802#endif
803 return ptr;
804}
805
806void
807__co_nmt_boot_free(void *ptr)
808{
809 free(ptr);
810}
811
812struct __co_nmt_boot *
813__co_nmt_boot_init(struct __co_nmt_boot *boot, can_net_t *net, co_dev_t *dev,
814 co_nmt_t *nmt)
815{
816 assert(boot);
817 assert(net);
818 assert(dev);
819 assert(nmt);
820
821 int errc = 0;
822
823 boot->net = net;
824 boot->dev = dev;
825 boot->nmt = nmt;
826
827 boot->state = NULL;
828
829 boot->recv = can_recv_create();
830 if (!boot->recv) {
831 errc = get_errc();
832 goto error_create_recv;
833 }
835
836 boot->timer = can_timer_create();
837 if (!boot->timer) {
838 errc = get_errc();
839 goto error_create_timer;
840 }
842
843 boot->id = 0;
844
845 boot->timeout = 0;
846 boot->sdo = NULL;
847
848 boot->start = (struct timespec){ 0, 0 };
849 can_net_get_time(boot->net, &boot->start);
850
851 boot->assignment = 0;
852 boot->ms = 0;
853
854 boot->st = 0;
855 boot->es = 0;
856
857 co_sdo_req_init(&boot->req);
858 boot->retry = 0;
859
861 return boot;
862
863 // can_timer_destroy(boot->timer);
864error_create_timer:
865 can_recv_destroy(boot->recv);
866error_create_recv:
867 set_errc(errc);
868 return NULL;
869}
870
871void
872__co_nmt_boot_fini(struct __co_nmt_boot *boot)
873{
874 assert(boot);
875
876 co_sdo_req_fini(&boot->req);
877
878 co_csdo_destroy(boot->sdo);
879
881 can_recv_destroy(boot->recv);
882}
883
886{
887 int errc = 0;
888
889 co_nmt_boot_t *boot = __co_nmt_boot_alloc();
890 if (!boot) {
891 errc = get_errc();
892 goto error_alloc_boot;
893 }
894
895 if (!__co_nmt_boot_init(boot, net, dev, nmt)) {
896 errc = get_errc();
897 goto error_init_boot;
898 }
899
900 return boot;
901
902error_init_boot:
903 __co_nmt_boot_free(boot);
904error_alloc_boot:
905 set_errc(errc);
906 return NULL;
907}
908
909void
911{
912 if (boot) {
913 __co_nmt_boot_fini(boot);
914 __co_nmt_boot_free(boot);
915 }
916}
917
918int
919co_nmt_boot_boot_req(co_nmt_boot_t *boot, co_unsigned8_t id, int timeout,
920 co_csdo_ind_t *dn_ind, co_csdo_ind_t *up_ind, void *data)
921{
922 assert(boot);
923
924 if (!id || id > CO_NUM_NODES) {
926 return -1;
927 }
928
929 if (boot->state != co_nmt_boot_wait_state) {
931 return -1;
932 }
933
934 boot->id = id;
935
936 boot->timeout = timeout;
937 co_csdo_destroy(boot->sdo);
938 boot->sdo = co_csdo_create(boot->net, NULL, boot->id);
939 if (!boot->sdo)
940 return -1;
941 co_csdo_set_timeout(boot->sdo, boot->timeout);
942 co_csdo_set_dn_ind(boot->sdo, dn_ind, data);
943 co_csdo_set_up_ind(boot->sdo, up_ind, data);
944
945 co_nmt_boot_emit_time(boot, NULL);
946
947 return 0;
948}
949
950static int
951co_nmt_boot_recv(const struct can_msg *msg, void *data)
952{
953 assert(msg);
954 co_nmt_boot_t *boot = data;
955 assert(boot);
956
957 co_nmt_boot_emit_recv(boot, msg);
958
959 return 0;
960}
961
962static int
963co_nmt_boot_timer(const struct timespec *tp, void *data)
964{
965 assert(tp);
966 co_nmt_boot_t *boot = data;
967 assert(boot);
968
969 co_nmt_boot_emit_time(boot, tp);
970
971 return 0;
972}
973
974static void
975co_nmt_boot_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
976 co_unsigned32_t ac, void *data)
977{
978 (void)sdo;
979 (void)idx;
980 (void)subidx;
981 co_nmt_boot_t *boot = data;
982 assert(boot);
983
984 co_nmt_boot_emit_dn_con(boot, ac);
985}
986
987static void
988co_nmt_boot_up_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
989 co_unsigned32_t ac, const void *ptr, size_t n, void *data)
990{
991 (void)sdo;
992 (void)idx;
993 (void)subidx;
994 co_nmt_boot_t *boot = data;
995 assert(boot);
996
997 co_nmt_boot_emit_up_con(boot, ac, ptr, n);
998}
999
1000static void
1001co_nmt_boot_cfg_con(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned32_t ac,
1002 void *data)
1003{
1004 (void)nmt;
1005 (void)id;
1006 co_nmt_boot_t *boot = data;
1007 assert(boot);
1008
1009 co_nmt_boot_emit_cfg_con(boot, ac);
1010}
1011
1012static void
1014{
1015 assert(boot);
1016
1017 while (next) {
1018 co_nmt_boot_state_t *prev = boot->state;
1019 boot->state = next;
1020
1021 if (prev && prev->on_leave)
1022 prev->on_leave(boot);
1023
1024 next = next->on_enter ? next->on_enter(boot) : NULL;
1025 }
1026}
1027
1028static inline void
1030{
1031 assert(boot);
1032 assert(boot->state);
1033 assert(boot->state->on_recv);
1034
1035 co_nmt_boot_enter(boot, boot->state->on_recv(boot, msg));
1036}
1037
1038static inline void
1040{
1041 assert(boot);
1042 assert(boot->state);
1043 assert(boot->state->on_time);
1044
1045 co_nmt_boot_enter(boot, boot->state->on_time(boot, tp));
1046}
1047
1048static inline void
1049co_nmt_boot_emit_dn_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
1050{
1051 assert(boot);
1052 assert(boot->state);
1053 assert(boot->state->on_dn_con);
1054
1055 co_nmt_boot_enter(boot, boot->state->on_dn_con(boot, ac));
1056}
1057
1058static inline void
1059co_nmt_boot_emit_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac,
1060 const void *ptr, size_t n)
1061{
1062 assert(boot);
1063 assert(boot->state);
1064 assert(boot->state->on_up_con);
1065
1066 co_nmt_boot_enter(boot, boot->state->on_up_con(boot, ac, ptr, n));
1067}
1068
1069static inline void
1070co_nmt_boot_emit_cfg_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
1071{
1072 assert(boot);
1073 assert(boot->state);
1074 assert(boot->state->on_cfg_con);
1075
1076 co_nmt_boot_enter(boot, boot->state->on_cfg_con(boot, ac));
1077}
1078
1079static co_nmt_boot_state_t *
1081{
1082 (void)boot;
1083 (void)tp;
1084
1085 boot->st = 0;
1086 boot->es = 0;
1087
1088 // Retrieve the slave assignment for the node.
1089 boot->assignment = co_dev_get_val_u32(boot->dev, 0x1f81, boot->id);
1090
1091 // Find the consumer heartbeat time for the node.
1092 boot->ms = 0;
1093 co_obj_t *obj_1016 = co_dev_find_obj(boot->dev, 0x1016);
1094 if (obj_1016) {
1095 co_unsigned8_t n = co_obj_get_val_u8(obj_1016, 0x00);
1096 for (size_t i = 1; i <= n; i++) {
1097 co_unsigned32_t val =
1098 co_obj_get_val_u32(obj_1016, i & 0xff);
1099 if (((val >> 16) & 0x7f) == boot->id)
1100 boot->ms = val & 0xffff;
1101 }
1102 }
1103
1104 // Abort the 'boot slave' process if the slave is not in the network
1105 // list.
1106 if (!(boot->assignment & 0x01)) {
1107 boot->es = 'A';
1109 }
1110
1111 if (!(boot->assignment & 0x04))
1112 // Skip booting and start the error control service.
1113 return co_nmt_boot_ec_state;
1114
1116}
1117
1118static co_nmt_boot_state_t *
1120{
1121 assert(boot);
1122
1123 can_recv_stop(boot->recv);
1124 can_timer_stop(boot->timer);
1125
1126 // If the node is already operational, end the 'boot slave' process with
1127 // error status L.
1128 if (!boot->es && (boot->st & ~CO_NMT_ST_TOGGLE) == CO_NMT_ST_START)
1129 boot->es = 'L';
1130
1131 // Retry on error status B (see Fig. 4 in CiA 302-2 version 4.1.0).
1132 if (boot->es == 'B') {
1133 int wait = 1;
1134 if (boot->assignment & 0x08) {
1135 // Obtain the time (in milliseconds) the master will
1136 // wait for a mandatory slave to boot.
1137 co_unsigned32_t boot_time = co_dev_get_val_u32(
1138 boot->dev, 0x1f89, 0x00);
1139 // Check if this time has elapsed.
1140 if (boot_time) {
1141 struct timespec now = { 0, 0 };
1142 can_net_get_time(boot->net, &now);
1143 wait = timespec_diff_msec(&now, &boot->start)
1144 < boot_time;
1145 }
1146 }
1147 // If the slave is not mandatory, or the boot time has not yet
1148 // elapsed, wait asynchronously for a while and retry the 'boot
1149 // slave' process.
1150 if (wait) {
1151 can_timer_timeout(boot->timer, boot->net,
1154 }
1155 }
1156
1158}
1159
1160static co_nmt_boot_state_t *
1162{
1163 (void)boot;
1164
1166}
1167
1168static void
1170{
1171 assert(boot);
1172
1173 co_nmt_boot_con(boot->nmt, boot->id, boot->st, boot->es);
1174}
1175
1176static co_nmt_boot_state_t *
1178{
1179 assert(boot);
1180
1181 boot->es = 'B';
1182
1183 // The device type check may follow an NMT 'reset communication'
1184 // command, in which case we may have to give the slave some time to
1185 // complete the state change. Start the first SDO request by simulating
1186 // a timeout.
1189 boot, CO_SDO_AC_TIMEOUT, NULL, 0);
1190}
1191
1192static co_nmt_boot_state_t *
1194 const void *ptr, size_t n)
1195{
1196 assert(boot);
1197
1198 // Retry the SDO request on timeout (this includes the first attempt).
1199 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1200 // Read the device type of the slave (object 1000).
1201 if (co_nmt_boot_up(boot, 0x1000, 0x00) == -1)
1203 return NULL;
1204 } else if (ac) {
1205#if !LELY_NO_STDIO
1206 diag(DIAG_ERROR, 0,
1207 "SDO abort code %08" PRIX32
1208 " received on upload request of object 1000 (Device type) to node %02X: %s",
1209 ac, boot->id, co_sdo_ac2str(ac));
1210#endif
1212 }
1213
1214 // If the expected device type (sub-object 1F84:ID) is 0, skip the check
1215 // and proceed with the vendor ID.
1216 co_unsigned32_t device_type =
1217 co_dev_get_val_u32(boot->dev, 0x1f84, boot->id);
1218 if (device_type && !co_nmt_boot_chk(boot, 0x1f84, boot->id, ptr, n)) {
1219 boot->es = 'C';
1221 }
1222
1223 can_recv_stop(boot->recv);
1225}
1226
1227static co_nmt_boot_state_t *
1229{
1230 assert(boot);
1231
1232 // If the expected vendor ID (sub-object 1F85:ID) is 0, skip the check
1233 // and proceed with the product code.
1234 co_unsigned32_t vendor_id =
1235 co_dev_get_val_u32(boot->dev, 0x1f85, boot->id);
1236 if (!vendor_id)
1238
1239 boot->es = 'D';
1240
1241 // Read the vendor ID of the slave (sub-object 1018:01).
1242 if (co_nmt_boot_up(boot, 0x1018, 0x01) == -1)
1244
1245 return NULL;
1246}
1247
1248static co_nmt_boot_state_t *
1250 const void *ptr, size_t n)
1251{
1252 assert(boot);
1253
1254#if !LELY_NO_STDIO
1255 if (ac)
1256 diag(DIAG_ERROR, 0,
1257 "SDO abort code %08" PRIX32
1258 " received on upload request of sub-object 1018:01 (Vendor-ID) to node %02X: %s",
1259 ac, boot->id, co_sdo_ac2str(ac));
1260#endif
1261
1262 if (ac || !co_nmt_boot_chk(boot, 0x1f85, boot->id, ptr, n))
1264
1266}
1267
1268static co_nmt_boot_state_t *
1270{
1271 assert(boot);
1272
1273 // If the expected product code (sub-object 1F86:ID) is 0, skip the
1274 // check and proceed with the revision number.
1275 co_unsigned32_t product_code =
1276 co_dev_get_val_u32(boot->dev, 0x1f86, boot->id);
1277 if (!product_code)
1279
1280 boot->es = 'M';
1281
1282 // Read the product code of the slave (sub-object 1018:02).
1283 if (co_nmt_boot_up(boot, 0x1018, 0x02) == -1)
1285
1286 return NULL;
1287}
1288
1289static co_nmt_boot_state_t *
1291 const void *ptr, size_t n)
1292{
1293 assert(boot);
1294
1295#if !LELY_NO_STDIO
1296 if (ac)
1297 diag(DIAG_ERROR, 0,
1298 "SDO abort code %08" PRIX32
1299 " received on upload request of sub-object 1018:02 (Product code) to node %02X: %s",
1300 ac, boot->id, co_sdo_ac2str(ac));
1301#endif
1302
1303 if (ac || !co_nmt_boot_chk(boot, 0x1f86, boot->id, ptr, n))
1305
1307}
1308
1309static co_nmt_boot_state_t *
1311{
1312 assert(boot);
1313
1314 // If the expected revision number (sub-object 1F87:ID) is 0, skip the
1315 // check and proceed with the serial number.
1316 co_unsigned32_t revision =
1317 co_dev_get_val_u32(boot->dev, 0x1f87, boot->id);
1318 if (!revision)
1320
1321 boot->es = 'N';
1322
1323 // Read the revision number of the slave (sub-object 1018:03).
1324 if (co_nmt_boot_up(boot, 0x1018, 0x03) == -1)
1326
1327 return NULL;
1328}
1329
1330static co_nmt_boot_state_t *
1332 const void *ptr, size_t n)
1333{
1334 assert(boot);
1335
1336#if !LELY_NO_STDIO
1337 if (ac)
1338 diag(DIAG_ERROR, 0,
1339 "SDO abort code %08" PRIX32
1340 " received on upload request of sub-object 1018:03 (Revision number) to node %02X: %s",
1341 ac, boot->id, co_sdo_ac2str(ac));
1342#endif
1343
1344 if (ac || !co_nmt_boot_chk(boot, 0x1f87, boot->id, ptr, n))
1346
1348}
1349
1350static co_nmt_boot_state_t *
1352{
1353 assert(boot);
1354
1355 // If the expected serial number (sub-object 1F88:ID) is 0, skip the
1356 // check and proceed to 'check node state'.
1357 co_unsigned32_t serial_nr =
1358 co_dev_get_val_u32(boot->dev, 0x1f88, boot->id);
1359 if (!serial_nr)
1361
1362 boot->es = 'O';
1363
1364 // Read the serial number of the slave (sub-object 1018:04).
1365 if (co_nmt_boot_up(boot, 0x1018, 0x04) == -1)
1367
1368 return NULL;
1369}
1370
1371static co_nmt_boot_state_t *
1373 const void *ptr, size_t n)
1374{
1375 assert(boot);
1376
1377#if !LELY_NO_STDIO
1378 if (ac)
1379 diag(DIAG_ERROR, 0,
1380 "SDO abort code %08" PRIX32
1381 " received on upload request of sub-object 1018:04 (Serial number) to node %02X: %s",
1382 ac, boot->id, co_sdo_ac2str(ac));
1383#endif
1384
1385 if (ac || !co_nmt_boot_chk(boot, 0x1f88, boot->id, ptr, n))
1387
1389}
1390
1391static co_nmt_boot_state_t *
1393{
1394 assert(boot);
1395
1396 // If the keep-alive bit is set, check the node state.
1397 if (boot->assignment & 0x10) {
1398 int ms;
1399 if (boot->ms) {
1400 boot->es = 'E';
1401 ms = boot->ms;
1402 } else {
1403 boot->es = 'F';
1404#if LELY_NO_CO_NG
1406#else
1408 // If we're not a heartbeat consumer, start node
1409 // guarding by sending the first RTR.
1411#endif
1412 }
1413
1414 // Start the CAN frame receiver for the heartbeat or node guard
1415 // message.
1416 can_recv_start(boot->recv, boot->net, CO_NMT_EC_CANID(boot->id),
1417 0);
1418 // Start the CAN timer in case we do not receive a heartbeat
1419 // indication or a node guard confirmation.
1420 can_timer_timeout(boot->timer, boot->net, ms);
1421
1422 return NULL;
1423 }
1424
1426}
1427
1428static co_nmt_boot_state_t *
1430{
1431 assert(boot);
1432 assert(msg);
1433 assert(msg->id == (uint_least32_t)CO_NMT_EC_CANID(boot->id));
1434
1435 can_timer_stop(boot->timer);
1436
1437 if (msg->len >= 1) {
1438 boot->st = msg->data[0];
1439 if ((boot->st & ~CO_NMT_ST_TOGGLE) == CO_NMT_ST_START)
1440 // If the node is already operational, skip the 'check
1441 // and update software version' and 'check
1442 // configuration' steps and proceed immediately to
1443 // 'start error control service'.
1444 return co_nmt_boot_ec_state;
1445 }
1446 boot->st = 0;
1447 // If the node is not operational, send the NMT 'reset
1448 // communication' command and proceed as if the keep-alive bit
1449 // was not set.
1452}
1453
1454static co_nmt_boot_state_t *
1456{
1457 (void)boot;
1458 (void)tp;
1459
1461}
1462
1463static void
1465{
1466 assert(boot);
1467
1468 can_recv_stop(boot->recv);
1469}
1470
1471static co_nmt_boot_state_t *
1473{
1474 assert(boot);
1475
1476 // Start the CAN frame receiver for the boot-up message.
1477 can_recv_start(boot->recv, boot->net, CO_NMT_EC_CANID(boot->id), 0);
1478 // Wait until we receive a boot-up message.
1481
1482 return NULL;
1483}
1484
1485static co_nmt_boot_state_t *
1487{
1488 (void)boot;
1489 (void)msg;
1490
1491 can_recv_stop(boot->recv);
1493}
1494
1495static co_nmt_boot_state_t *
1497{
1498 (void)boot;
1499 (void)tp;
1500
1502}
1503
1504static co_nmt_boot_state_t *
1506{
1507 assert(boot);
1508
1509 if (boot->assignment & 0x20) {
1510 boot->es = 'G';
1511
1512 // Abort if the expected program software identification
1513 // (sub-object 1F55:ID) is 0.
1514 co_unsigned32_t sw_id =
1515 co_dev_get_val_u32(boot->dev, 0x1f55, boot->id);
1516 if (!sw_id)
1518
1519 // The software version check may follow an NMT 'reset
1520 // communication' command, in which case we may have to give the
1521 // slave some time to complete the state change. Start the first
1522 // SDO request by simulating a timeout.
1525 boot, CO_SDO_AC_TIMEOUT, NULL, 0);
1526 }
1527
1528 // Continue with the 'check configuration' step if the software version
1529 // check is not necessary.
1531}
1532
1533static co_nmt_boot_state_t *
1535 const void *ptr, size_t n)
1536{
1537 assert(boot);
1538
1539 // Retry the SDO request on timeout (this includes the first attempt).
1540 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1541 // Read the program software identification of the slave
1542 // (sub-object 1F56:01).
1543 if (co_nmt_boot_up(boot, 0x1f56, 0x01) == -1)
1545 return NULL;
1546 } else if (ac) {
1547#if !LELY_NO_STDIO
1548 diag(DIAG_ERROR, 0,
1549 "SDO abort code %08" PRIX32
1550 " received on upload request of sub-object 1F56:01 (Program software identification) to node %02X: %s",
1551 ac, boot->id, co_sdo_ac2str(ac));
1552#endif
1554 }
1555
1556 // If the program software identification matches the expected value,
1557 // proceed to 'check configuration'.
1558 if (co_nmt_boot_chk(boot, 0x1f55, boot->id, ptr, n))
1560
1561 // Do not update the software if software update (bit 6) is not allowed
1562 // or if the keep-alive bit (bit 4) is set.
1563 if ((boot->assignment & 0x50) != 0x40) {
1564 boot->es = 'H';
1566 }
1567
1568 boot->es = 'I';
1569
1571}
1572
1573static co_nmt_boot_state_t *
1575{
1576 assert(boot);
1577
1578 // Read the program control of the slave (sub-object 1F51:01).
1579 if (co_nmt_boot_up(boot, 0x1f51, 0x01) == -1)
1581
1582 return NULL;
1583}
1584
1585static co_nmt_boot_state_t *
1587{
1588#if LELY_NO_STDIO
1589 (void)boot;
1590#else
1591 assert(boot);
1592#endif
1593
1594 // The download SDO request may be unconfirmed on some devices since it
1595 // stops the program on the slave (and may cause a restart of the
1596 // bootloader). We therefore ignore timeouts.
1597 if (ac && ac != CO_SDO_AC_TIMEOUT) {
1598#if !LELY_NO_STDIO
1599 diag(DIAG_ERROR, 0,
1600 "SDO abort code %08" PRIX32
1601 " received on download request of sub-object 1F51:01 (Program control) to node %02X: %s",
1602 ac, boot->id, co_sdo_ac2str(ac));
1603#endif
1605 }
1606
1608}
1609
1610static co_nmt_boot_state_t *
1612 const void *ptr, size_t n)
1613{
1614 assert(boot);
1615
1616 // If the value is already 0 (Program stopped), do not write a 0 (Stop
1617 // program), but skip to the 'clear program' state.
1618 co_unsigned8_t val = 0;
1619 // clang-format off
1620 if (!ac && co_val_read(CO_DEFTYPE_UNSIGNED8, &val, ptr,
1621 (const uint_least8_t *)ptr + n) && !val)
1622 // clang-format on
1624
1625 // Write a 0 (Stop program) to the program control of the slave
1626 // (sub-object 1F51:01).
1627 // clang-format off
1628 if (co_nmt_boot_dn(boot, 0x1f51, 0x01, CO_DEFTYPE_UNSIGNED8,
1629 &(co_unsigned8_t){ 0 }) == -1)
1630 // clang-format on
1632
1633 return NULL;
1634}
1635
1636static co_nmt_boot_state_t *
1638{
1639 assert(boot);
1640
1641 // The 'clear program' command follows the 'stop program' command, which
1642 // may have triggered a reboot of the slave. In that case we may have to
1643 // give the slave some time to finish booting. Start the first SDO
1644 // request by simulating a timeout.
1647}
1648
1649static co_nmt_boot_state_t *
1651{
1652 assert(boot);
1653
1654 // Retry the SDO request on timeout.
1655 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1656 // Write a 3 (Clear program) to the program control of the slave
1657 // (sub-object 1F51:01).
1658 // clang-format off
1659 if (co_nmt_boot_dn(boot, 0x1f51, 0x01, CO_DEFTYPE_UNSIGNED8,
1660 &(co_unsigned8_t){ 3 }) == -1)
1661 // clang-format on
1663 return NULL;
1664 } else if (ac) {
1665#if !LELY_NO_STDIO
1666 diag(DIAG_ERROR, 0,
1667 "SDO abort code %08" PRIX32
1668 " received on download request of sub-object 1F51:01 (Program control) to node %02X: %s",
1669 ac, boot->id, co_sdo_ac2str(ac));
1670#endif
1672 }
1673
1675}
1676
1677static co_nmt_boot_state_t *
1679{
1680 assert(boot);
1681
1682 co_sub_t *sub = co_dev_find_sub(boot->dev, 0x1f58, boot->id);
1683 if (!sub)
1685
1686 // Upload the program data.
1687 struct co_sdo_req *req = &boot->req;
1688 co_sdo_req_clear(req);
1689 co_unsigned32_t ac = co_sub_up_ind(sub, req);
1690 if (ac || !co_sdo_req_first(req) || !co_sdo_req_last(req)) {
1691#if !LELY_NO_STDIO
1692 if (ac)
1693 diag(DIAG_ERROR, 0,
1694 "SDO abort code %08" PRIX32
1695 " on upload request of object 1F58:%02X (Program data): %s",
1696 ac, boot->id, co_sdo_ac2str(ac));
1697#endif
1699 }
1700
1701 // The 'clear program' step may take some time to complete, causing an
1702 // immediate 'download program' to generate a timeout. Start the first
1703 // attempt by simulating a timeout.
1706}
1707
1708static co_nmt_boot_state_t *
1710{
1711 (void)boot;
1712
1713 // Retry the SDO request on timeout (this includes the first attempt).
1714 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1715 struct co_sdo_req *req = &boot->req;
1716 // Write the program data (sub-object 1F58:ID) to the program
1717 // data of the slave (sub-object 1F50:01) using SDO block
1718 // transfer.
1719 // clang-format off
1720 if (co_csdo_blk_dn_req(boot->sdo, 0x1f50, 0x01, req->buf,
1721 req->size, &co_nmt_boot_dn_con, boot) == -1)
1722 // clang-format on
1724 return NULL;
1725 } else if (ac) {
1726 // If SDO block transfer is not supported, fall back to SDO
1727 // segmented transfer.
1729 }
1730
1732}
1733
1734static co_nmt_boot_state_t *
1736{
1737 assert(boot);
1738
1739 // If SDO block transfer is not supported, we may still have to wait for
1740 // the 'clear program' step to complete before successfully doing a
1741 // segmented SDO transfer. Start the first attempt by simulating a
1742 // timeout.
1745}
1746
1747static co_nmt_boot_state_t *
1749{
1750 assert(boot);
1751
1752 // Retry the SDO request on timeout (this includes the first attempt).
1753 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1754 struct co_sdo_req *req = &boot->req;
1755 // Write the program data (sub-object 1F58:ID) to the program
1756 // data of the slave (sub-object 1F50:01) using SDO segmented
1757 // transfer.
1758 // clang-format off
1759 if (co_csdo_dn_req(boot->sdo, 0x1f50, 0x01, req->buf, req->size,
1760 &co_nmt_boot_dn_con, boot) == -1)
1761 // clang-format on
1763 return NULL;
1764 } else if (ac) {
1765#if !LELY_NO_STDIO
1766 diag(DIAG_ERROR, 0,
1767 "SDO abort code %08" PRIX32
1768 " received on download request of sub-object 1F50:01 (Program data) to node %02X: %s",
1769 ac, boot->id, co_sdo_ac2str(ac));
1770#endif
1772 }
1773
1775}
1776
1777static co_nmt_boot_state_t *
1779{
1780 assert(boot);
1781
1782 // Wait for a while before checking the flash status indication.
1785
1786 return NULL;
1787}
1788
1789static co_nmt_boot_state_t *
1791{
1792 assert(boot);
1793 (void)tp;
1794
1795 // Read the flash status indication of the slave (sub-object 1F57:01).
1796 if (co_nmt_boot_up(boot, 0x1f57, 0x01) == -1)
1798
1799 return NULL;
1800}
1801
1802static co_nmt_boot_state_t *
1804 const void *ptr, size_t n)
1805{
1806#if LELY_NO_STDIO
1807 (void)boot;
1808 (void)ac;
1809#else
1810 assert(boot);
1811
1812 if (ac)
1813 diag(DIAG_ERROR, 0,
1814 "SDO abort code %08" PRIX32
1815 " received on upload request of sub-object 1F57:01 (Flash status indication) to node %02X: %s",
1816 ac, boot->id, co_sdo_ac2str(ac));
1817#endif
1818
1819 // If the flash status indication is not valid, try again.
1820 co_unsigned32_t val = 0;
1821 // clang-format off
1822 if (!co_val_read(CO_DEFTYPE_UNSIGNED32, &val, ptr,
1823 (const uint_least8_t *)ptr + n) || (val & 0x01))
1824 // clang-format on
1826
1827 co_unsigned8_t st = (val >> 1) & 0x7f;
1828 switch (st) {
1829 case 0: return co_nmt_boot_chk_prog_state;
1830 case 1:
1831 diag(DIAG_ERROR, 0,
1832 "flash status identification %d: No valid program available",
1833 st);
1834 break;
1835 case 2:
1836 diag(DIAG_ERROR, 0,
1837 "flash status identification %d: Data format unknown",
1838 st);
1839 break;
1840 case 3:
1841 diag(DIAG_ERROR, 0,
1842 "flash status identification %d: Data format error or data CRC error",
1843 st);
1844 break;
1845 case 4:
1846 diag(DIAG_ERROR, 0,
1847 "flash status identification %d: Flash not cleared before write",
1848 st);
1849 break;
1850 case 5:
1851 diag(DIAG_ERROR, 0,
1852 "flash status identification %d: Flash write error",
1853 st);
1854 break;
1855 case 6:
1856 diag(DIAG_ERROR, 0,
1857 "flash status identification %d: General address error",
1858 st);
1859 break;
1860 case 7:
1861 diag(DIAG_ERROR, 0,
1862 "flash status identification %d: Flash secured (= write access currently forbidden)",
1863 st);
1864 break;
1865 case 63:
1866 diag(DIAG_ERROR, 0,
1867 "flash status identification %d: Unspecified error",
1868 st);
1869 break;
1870 default:
1871#if !LELY_NO_STDIO
1872 if (st > 63)
1873 diag(DIAG_ERROR, 0,
1874 "flash status identification %d: Manufacturer-specific error: 0x%08" PRIX32
1875 "",
1876 st, (val >> 16) & 0xffff);
1877#endif
1878 break;
1879 }
1880
1882}
1883
1884static co_nmt_boot_state_t *
1886{
1887 assert(boot);
1888
1889 // Read the program software identification of the slave (sub-object
1890 // 1F56:01).
1891 if (co_nmt_boot_up(boot, 0x1f56, 0x01) == -1)
1893
1894 return NULL;
1895}
1896
1897static co_nmt_boot_state_t *
1899 const void *ptr, size_t n)
1900{
1901 assert(boot);
1902
1903#if !LELY_NO_STDIO
1904 if (ac)
1905 diag(DIAG_ERROR, 0,
1906 "SDO abort code %08" PRIX32
1907 " received on upload request of sub-object 1F56:01 (Program software identification) to node %02X: %s",
1908 ac, boot->id, co_sdo_ac2str(ac));
1909#endif
1910
1911 if (ac || !co_nmt_boot_chk(boot, 0x1f55, boot->id, ptr, n))
1913
1915}
1916
1917static co_nmt_boot_state_t *
1919{
1920 assert(boot);
1921
1922 // Write a 1 (Start program) to the program control of the slave
1923 // (sub-object 1F51:01).
1924 // clang-format off
1925 if (co_nmt_boot_dn(boot, 0x1f51, 0x01, CO_DEFTYPE_UNSIGNED8,
1926 &(co_unsigned8_t){ 1 }) == -1)
1927 // clang-format on
1929
1930 return NULL;
1931}
1932
1933static co_nmt_boot_state_t *
1935{
1936#if LELY_NO_STDIO
1937 (void)boot;
1938#else
1939 assert(boot);
1940#endif
1941
1942 // The download SDO request may be unconfirmed on some devices since it
1943 // starts the program on the slave (and may cause a restart of the
1944 // program). We therefore ignore timeouts.
1945 if (ac && ac != CO_SDO_AC_TIMEOUT) {
1946#if !LELY_NO_STDIO
1947 diag(DIAG_ERROR, 0,
1948 "SDO abort code %08" PRIX32
1949 " received on download request of sub-object 1F51:01 (Program control) to node %02X: %s",
1950 ac, boot->id, co_sdo_ac2str(ac));
1951#endif
1953 }
1954
1956}
1957
1958static co_nmt_boot_state_t *
1960{
1961 assert(boot);
1962
1963 // Wait for a while before checking the program control.
1966
1967 return NULL;
1968}
1969
1970static co_nmt_boot_state_t *
1972{
1973 assert(boot);
1974 (void)tp;
1975
1976 // The 'start program' step may take some time to complete, causing an
1977 // immediate SDO upload request to generate a timeout. Start the first
1978 // attempt by simulating a timeout.
1981 boot, CO_SDO_AC_TIMEOUT, NULL, 0);
1982
1983 return NULL;
1984}
1985
1986static co_nmt_boot_state_t *
1988 const void *ptr, size_t n)
1989{
1990 assert(boot);
1991
1992 // Retry the SDO request on timeout (this includes the first attempt).
1993 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1994 // Read the program control of the slave (sub-object 1F51:01).
1995 if (co_nmt_boot_up(boot, 0x1f51, 0x01) == -1)
1997 return NULL;
1998 } else if (ac) {
1999#if !LELY_NO_STDIO
2000 diag(DIAG_ERROR, 0,
2001 "SDO abort code %08" PRIX32
2002 " received on upload request of sub-object 1F51:01 (Program control) to node %02X: %s",
2003 ac, boot->id, co_sdo_ac2str(ac));
2004#endif
2006 }
2007
2008 // If the program control differs from 'Program started', try again.
2009 co_unsigned8_t val = 0;
2010 const uint_least8_t *const begin = ptr;
2011 const uint_least8_t *const end = begin != NULL ? begin + n : NULL;
2012 // clang-format off
2013 if (!co_val_read(CO_DEFTYPE_UNSIGNED8, &val, begin, end) || val != 1)
2014 // clang-format on
2016
2018}
2019
2020static co_nmt_boot_state_t *
2022{
2023 assert(boot);
2024
2025 boot->es = 'J';
2026
2027 // If the expected configuration date (sub-object 1F26:ID) or time
2028 // (sub-object 1F27:ID) are not configured, proceed to 'update
2029 // configuration'.
2030 co_unsigned32_t cfg_date =
2031 co_dev_get_val_u32(boot->dev, 0x1f26, boot->id);
2032 co_unsigned32_t cfg_time =
2033 co_dev_get_val_u32(boot->dev, 0x1f27, boot->id);
2034 if (!cfg_date || !cfg_time)
2036
2037 // The configuration check may follow an NMT 'reset communication'
2038 // command (if the 'check software version' step was skipped), in which
2039 // case we may have to give the slave some time to complete the state
2040 // change. Start the first SDO request by simulating a timeout.
2043 boot, CO_SDO_AC_TIMEOUT, NULL, 0);
2044}
2045
2046static co_nmt_boot_state_t *
2048 const void *ptr, size_t n)
2049{
2050 assert(boot);
2051
2052 // Retry the SDO request on timeout (this includes the first attempt).
2053 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
2054 // Read the configuration date of the slave (sub-object
2055 // 1020:01).
2056 if (co_nmt_boot_up(boot, 0x1020, 0x01) == -1)
2058 return NULL;
2059#if !LELY_NO_STDIO
2060 } else if (ac) {
2061 diag(DIAG_ERROR, 0,
2062 "SDO abort code %08" PRIX32
2063 " received on upload request of sub-object 1020:01 (Configuration date) to node %02X: %s",
2064 ac, boot->id, co_sdo_ac2str(ac));
2065#endif
2066 }
2067
2068 // If the configuration date does not match the expected value, skip
2069 // checking the time and proceed to 'update configuration'.
2070 if (ac || !co_nmt_boot_chk(boot, 0x1f26, boot->id, ptr, n))
2072
2073 // Read the configuration time of the slave (sub-object 1020:02).
2074 if (co_nmt_boot_up(boot, 0x1020, 0x02) == -1)
2076
2078}
2079
2080static co_nmt_boot_state_t *
2082 const void *ptr, size_t n)
2083{
2084 assert(boot);
2085
2086#if !LELY_NO_STDIO
2087 if (ac)
2088 diag(DIAG_ERROR, 0,
2089 "SDO abort code %08" PRIX32
2090 " received on upload request of sub-object 1020:02 (Configuration time) to node %02X: %s",
2091 ac, boot->id, co_sdo_ac2str(ac));
2092#endif
2093
2094 // If the configuration time does not match the expected value, proceed
2095 // to 'update configuration'.
2096 if (ac || !co_nmt_boot_chk(boot, 0x1f27, boot->id, ptr, n))
2098
2099 return co_nmt_boot_ec_state;
2100}
2101
2102static co_nmt_boot_state_t *
2104{
2105 assert(boot);
2106
2107 boot->es = 'J';
2108
2109 // clang-format off
2110 if (co_nmt_cfg_req(boot->nmt, boot->id, boot->timeout,
2111 &co_nmt_boot_cfg_con, boot) == -1)
2112 // clang-format on
2114
2115 return NULL;
2116}
2117
2118static co_nmt_boot_state_t *
2120{
2121#if LELY_NO_STDIO
2122 (void)boot;
2123#else
2124 assert(boot);
2125#endif
2126
2127 if (ac) {
2128#if !LELY_NO_STDIO
2129 diag(DIAG_ERROR, 0,
2130 "SDO abort code %08" PRIX32
2131 " received while updating the configuration of node %02X: %s",
2132 ac, boot->id, co_sdo_ac2str(ac));
2133#endif
2135 }
2136
2137 return co_nmt_boot_ec_state;
2138}
2139
2140static co_nmt_boot_state_t *
2142{
2143 assert(boot);
2144
2145 if (boot->ms) {
2146 boot->es = 'K';
2147 // Start the CAN frame receiver for heartbeat messages.
2148 can_recv_start(boot->recv, boot->net, CO_NMT_EC_CANID(boot->id),
2149 0);
2150 // Wait for the first heartbeat indication.
2151 can_timer_timeout(boot->timer, boot->net, boot->ms);
2152 return NULL;
2153#if !LELY_NO_CO_NG
2154 } else if (boot->assignment & 0x01) {
2155 // If the guard time is non-zero, start node guarding by sending
2156 // the first RTR, but do not wait for the response.
2157 co_unsigned16_t gt = (boot->assignment >> 16) & 0xffff;
2158 if (gt)
2160#endif
2161 }
2162
2163 boot->es = 0;
2165}
2166
2167static co_nmt_boot_state_t *
2169{
2170 assert(boot);
2171 assert(msg);
2172 assert(msg->id == (uint_least32_t)CO_NMT_EC_CANID(boot->id));
2173
2174 if (msg->len >= 1) {
2175 co_unsigned8_t st = msg->data[0];
2176 // Do not consider a boot-up message to be a heartbeat message.
2177 if (st == CO_NMT_ST_BOOTUP)
2178 return NULL;
2179 boot->st = st;
2180 boot->es = 0;
2181 }
2182
2184}
2185
2186static co_nmt_boot_state_t *
2188{
2189 (void)boot;
2190 (void)tp;
2191
2193}
2194
2195static int
2196co_nmt_boot_dn(co_nmt_boot_t *boot, co_unsigned16_t idx, co_unsigned8_t subidx,
2197 co_unsigned16_t type, const void *val)
2198{
2199 assert(boot);
2200
2201 return co_csdo_dn_val_req(boot->sdo, idx, subidx, type, val,
2202 &co_nmt_boot_dn_con, boot);
2203}
2204
2205static int
2206co_nmt_boot_up(co_nmt_boot_t *boot, co_unsigned16_t idx, co_unsigned8_t subidx)
2207{
2208 assert(boot);
2209
2210 return co_csdo_up_req(
2211 boot->sdo, idx, subidx, &co_nmt_boot_up_con, boot);
2212}
2213
2214static int
2215co_nmt_boot_chk(co_nmt_boot_t *boot, co_unsigned16_t idx, co_unsigned8_t subidx,
2216 const void *ptr, size_t n)
2217{
2218 assert(boot);
2219
2220 co_sub_t *sub = co_dev_find_sub(boot->dev, idx, subidx);
2221 if (!sub)
2222 return 0;
2223 co_unsigned16_t type = co_sub_get_type(sub);
2224 assert(!co_type_is_array(type));
2225
2226 union co_val val;
2227 if (!co_val_read(type, &val, ptr, (const uint_least8_t *)ptr + n))
2228 return 0;
2229
2230 return !co_val_cmp(type, &val, co_sub_get_val(sub));
2231}
2232
2233#if !LELY_NO_CO_NG
2234static int
2236{
2237 assert(boot);
2238
2239 struct can_msg msg = CAN_MSG_INIT;
2240 msg.id = CO_NMT_EC_CANID(boot->id);
2241 msg.flags |= CAN_FLAG_RTR;
2242
2243 return can_net_send(boot->net, &msg);
2244}
2245#endif
2246
2247#endif // !LELY_NO_CO_MASTER && !LELY_NO_CO_NMT_BOOT
@ CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames).
Definition msg.h:48
#define CAN_MSG_INIT
The static initializer for can_msg.
Definition msg.h:113
This header file is part of the CANopen library; it contains the device description declarations.
co_obj_t * co_dev_find_obj(const co_dev_t *dev, co_unsigned16_t idx)
Finds an object in the object dictionary of a CANopen device.
Definition dev.c:279
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:290
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition dev.h:56
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
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
void co_csdo_set_timeout(co_csdo_t *sdo, int timeout)
Sets the timeout of a Client-SDO.
Definition csdo.c:1142
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
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
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
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_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
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
void co_csdo_destroy(co_csdo_t *sdo)
Destroys a CANopen Client-SDO service.
Definition csdo.c:1024
This header file is part of the utilities library; it contains the diagnostic declarations.
@ DIAG_ERROR
An error.
Definition diag.h:57
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition diag.c:171
@ ERRNUM_INVAL
Invalid argument.
Definition errnum.h:132
@ ERRNUM_INPROGRESS
Operation in progress.
Definition errnum.h:128
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition errnum.c:932
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition errnum.c:944
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition errnum.c:46
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition errnum.h:424
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:343
void co_sdo_req_fini(struct co_sdo_req *req)
Finalizes a CANopen SDO upload/download request.
Definition sdo.c:121
void co_sdo_req_clear(struct co_sdo_req *req)
Clears a CANopen SDO upload/download request, including its buffer.
Definition sdo.c:129
const char * co_sdo_ac2str(co_unsigned32_t ac)
Returns a string describing an SDO abort code.
Definition sdo.c:57
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
void co_sdo_req_init(struct co_sdo_req *req)
Initializes a CANopen SDO upload/download request.
Definition sdo.c:109
#define CO_SDO_AC_TIMEOUT
SDO abort code: SDO protocol timed out.
Definition sdo.h:66
void can_timer_stop(can_timer_t *timer)
Stops a CAN timer and unregisters it with a network interface.
Definition net.c:462
int can_net_send(can_net_t *net, const struct can_msg *msg)
Sends a CAN frame from a network interface.
Definition net.c:300
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition net.c:376
void can_net_get_time(const can_net_t *net, struct timespec *tp)
Retrieves the current time of a CAN network interface.
Definition net.c:196
void can_timer_set_func(can_timer_t *timer, can_timer_func_t *func, void *data)
Sets the callback function invoked when a CAN timer is triggered.
Definition net.c:422
void can_recv_stop(can_recv_t *recv)
Stops a CAN frame receiver from processing frames and unregisters it with the network interface.
Definition net.c:609
void can_recv_set_func(can_recv_t *recv, can_recv_func_t *func, void *data)
Sets the callback function used to process CAN frames with a receiver.
Definition net.c:578
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition net.c:558
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
void can_recv_start(can_recv_t *recv, can_net_t *net, uint_least32_t id, uint_least8_t flags)
Registers a CAN frame receiver with a network interface and starts processing frames.
Definition net.c:587
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition net.c:533
void can_timer_destroy(can_timer_t *timer)
Destroys a CAN timer.
Definition net.c:401
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:2297
#define CO_NMT_ST_BOOTUP
The NMT state 'boot-up'.
Definition nmt.h:55
#define CO_NMT_EC_CANID(id)
The CAN identifier used for both node guarding and heartbeat monitoring.
Definition nmt.h:76
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:1979
#define CO_NMT_ST_START
The NMT state 'operational'.
Definition nmt.h:61
#define CO_NMT_ST_TOGGLE
The mask to get/set the toggle bit from an NMT state.
Definition nmt.h:73
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:1806
#define CO_NMT_CS_RESET_COMM
The NMT command specifier 'reset communication'.
Definition nmt.h:52
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:1486
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:2119
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:414
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:508
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:694
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:1049
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:1161
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:1310
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:1959
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:1392
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:589
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:2187
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:1918
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:1898
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:546
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:2215
static co_nmt_boot_state_t *const co_nmt_boot_up_cfg_state
The 'update configuration' state (see Fig.
Definition nmt_boot.c:714
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:2168
#define LELY_CO_NMT_BOOT_RTR_TIMEOUT
The timeout (in milliseconds) after sending a node guarding RTR.
Definition nmt_boot.c:54
static void co_nmt_boot_error_on_leave(co_nmt_boot_t *boot)
The exit function of the 'error' state.
Definition nmt_boot.c:1169
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:1070
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:1650
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:1678
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:2021
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:1177
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:2081
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:1778
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:1987
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:1013
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:988
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:1748
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:655
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:1080
void co_nmt_boot_destroy(co_nmt_boot_t *boot)
Destroys a CANopen NMT 'boot slave' service.
Definition nmt_boot.c:910
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:1372
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:1001
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:1637
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:1611
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:374
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:1885
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:1534
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:2047
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:2141
#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:71
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:440
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:1709
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:975
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:1269
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:963
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:1039
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:394
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:1429
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:737
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:1249
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:1586
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:919
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:354
#define LELY_CO_NMT_BOOT_WAIT_TIMEOUT
The timeout (in milliseconds) before trying to boot the slave again.
Definition nmt_boot.c:43
#define LELY_CO_NMT_BOOT_RESET_TIMEOUT
The timeout (in milliseconds) after sending the NMT 'reset communication' command.
Definition nmt_boot.c:63
static int co_nmt_boot_send_rtr(co_nmt_boot_t *boot)
Sends a node guarding RTR to the slave.
Definition nmt_boot.c:2235
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:1934
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:2196
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:626
static co_nmt_boot_state_t *const co_nmt_boot_wait_state
The 'wait asynchronously' state.
Definition nmt_boot.c:290
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:607
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:1790
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:564
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:1193
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:1735
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:464
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:1464
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:885
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:2206
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:951
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:1351
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:1059
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:1228
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:1574
static co_nmt_boot_state_t *const co_nmt_boot_error_state
The 'error' state.
Definition nmt_boot.c:314
#define LELY_CO_NMT_BOOT_SDO_RETRY
The number of times an SDO request is retried after a timeout.
Definition nmt_boot.c:48
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:1455
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:334
static co_nmt_boot_state_t *const co_nmt_boot_abort_state
The 'abort' state.
Definition nmt_boot.c:300
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:677
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:1290
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:482
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:1331
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:1505
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:527
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:2103
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:1971
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:1119
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:1803
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:1029
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:1472
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:1496
This is the internal header file of the NMT 'boot slave' declarations.
This header file is part of the CANopen library; it contains the object dictionary declarations.
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:712
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_unsigned16_t co_sub_get_type(const co_sub_t *sub)
Returns the data type of a CANopen sub-object.
Definition obj.c:603
This is the internal header file of the CANopen library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
A CAN network interface.
Definition net.c:37
A CAN frame receiver.
Definition net.c:86
A CAN timer.
Definition net.c:63
A CANopen Client-SDO.
Definition csdo.c:71
A CANopen device.
Definition dev.h:30
A CANopen NMT 'boot slave' state.
Definition nmt_boot.c:215
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:217
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:261
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:248
void(* on_leave)(co_nmt_boot_t *boot)
A pointer to the function invoked when the current state is left.
Definition nmt_boot.c:275
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:272
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:237
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:227
A CANopen NMT 'boot slave' service.
Definition nmt_boot.c:79
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition nmt_boot.c:89
struct co_sdo_req req
The CANopen SDO upload request used for reading sub-objects.
Definition nmt_boot.c:105
can_timer_t * timer
A pointer to the CAN timer.
Definition nmt_boot.c:91
co_nmt_t * nmt
A pointer to an NMT master service.
Definition nmt_boot.c:85
can_net_t * net
A pointer to a CAN network interface.
Definition nmt_boot.c:81
co_nmt_boot_state_t * state
A pointer to the current state.
Definition nmt_boot.c:87
co_unsigned32_t assignment
The NMT slave assignment (object 1F81).
Definition nmt_boot.c:101
co_unsigned16_t ms
The consumer heartbeat time (in milliseconds).
Definition nmt_boot.c:103
int retry
The number of SDO retries remaining.
Definition nmt_boot.c:107
co_csdo_t * sdo
A pointer to the Client-SDO used to access slave objects.
Definition nmt_boot.c:97
co_unsigned8_t id
The node-ID.
Definition nmt_boot.c:93
co_dev_t * dev
A pointer to a CANopen device.
Definition nmt_boot.c:83
char es
The error status.
Definition nmt_boot.c:111
struct timespec start
The time at which the 'boot slave' request was received.
Definition nmt_boot.c:99
int timeout
The SDO timeout (in milliseconds).
Definition nmt_boot.c:95
co_unsigned8_t st
The state of the node (including the toggle bit).
Definition nmt_boot.c:109
A CANopen NMT master/slave service.
Definition nmt.c:148
A CANopen object.
Definition obj.h:31
A CANopen sub-object.
Definition obj.h:53
A CAN or CAN FD format frame.
Definition msg.h:87
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition msg.h:102
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition msg.h:89
uint_least8_t flags
The flags (any combination of CAN_FLAG_IDE, CAN_FLAG_RTR, CAN_FLAG_FDF, CAN_FLAG_BRS and CAN_FLAG_ESI...
Definition msg.h:94
uint_least8_t len
The number of bytes in data (or the requested number of bytes in case of a remote frame).
Definition msg.h:100
A CANopen SDO upload/download request.
Definition sdo.h:181
size_t size
The total size (in bytes) of the value to be uploaded/downloaded.
Definition sdo.h:187
const void * buf
A pointer to the next bytes to be uploaded/downloaded.
Definition sdo.h:189
A time type with nanosecond resolution.
Definition time.h:88
int co_type_is_array(co_unsigned16_t type)
Returns 1 if the specified (static) data type is an array, and 0 if not.
Definition type.c:40
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition type.h:44
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition type.h:50
A union of the CANopen static data types.
Definition val.h:273
This header file is part of the utilities library; it contains the time function declarations.
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:221
This header file is part of the CANopen library; it contains the CANopen value declarations.
size_t co_val_read(co_unsigned16_t type, void *val, const uint_least8_t *begin, const uint_least8_t *end)
Reads a value of the specified data type from a memory buffer.
Definition val.c:451
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:369