Lely core libraries 1.9.2
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
41#define LELY_CO_NMT_BOOT_WAIT_TIMEOUT 1000
42#endif
43
44#ifndef LELY_CO_NMT_BOOT_SDO_RETRY
46#define LELY_CO_NMT_BOOT_SDO_RETRY 3
47#endif
48
49#ifndef LELY_CO_NMT_BOOT_RTR_TIMEOUT
51#define LELY_CO_NMT_BOOT_RTR_TIMEOUT 100
52#endif
53
54#ifndef LELY_CO_NMT_BOOT_CHECK_TIMEOUT
59#define LELY_CO_NMT_BOOT_CHECK_TIMEOUT 100
60#endif
61
65
81 co_unsigned8_t id;
89 co_unsigned32_t assignment;
91 co_unsigned16_t ms;
95 int retry;
97 co_unsigned8_t st;
99 char es;
100};
101
107static int co_nmt_boot_recv(const struct can_msg *msg, void *data);
108
114static int co_nmt_boot_timer(const struct timespec *tp, void *data);
115
122static void co_nmt_boot_dn_con(co_csdo_t *sdo, co_unsigned16_t idx,
123 co_unsigned8_t subidx, co_unsigned32_t ac, void *data);
124
131static void co_nmt_boot_up_con(co_csdo_t *sdo, co_unsigned16_t idx,
132 co_unsigned8_t subidx, co_unsigned32_t ac, const void *ptr,
133 size_t n, void *data);
134
141static void co_nmt_boot_cfg_con(co_nmt_t *nmt, co_unsigned8_t id,
142 co_unsigned32_t ac, void *data);
143
148static void co_nmt_boot_enter(co_nmt_boot_t *boot, co_nmt_boot_state_t *next);
149
157static inline void co_nmt_boot_emit_time(
158 co_nmt_boot_t *boot, const struct timespec *tp);
159
167static inline void co_nmt_boot_emit_recv(
168 co_nmt_boot_t *boot, const struct can_msg *msg);
169
177static inline void co_nmt_boot_emit_dn_con(
178 co_nmt_boot_t *boot, co_unsigned32_t ac);
179
189static inline void co_nmt_boot_emit_up_con(co_nmt_boot_t *boot,
190 co_unsigned32_t ac, const void *ptr, size_t n);
191
199static inline void co_nmt_boot_emit_cfg_con(
200 co_nmt_boot_t *boot, co_unsigned32_t ac);
201
215 co_nmt_boot_t *boot, const struct timespec *tp);
226 co_nmt_boot_t *boot, const struct can_msg *msg);
236 co_nmt_boot_state_t *(*on_dn_con)(
237 co_nmt_boot_t *boot, co_unsigned32_t ac);
250 co_unsigned32_t ac, const void *ptr, size_t n);
260 co_nmt_boot_state_t *(*on_cfg_con)(
261 co_nmt_boot_t *boot, co_unsigned32_t ac);
263 void (*on_leave)(co_nmt_boot_t *boot);
264};
265
266#define LELY_CO_DEFINE_STATE(name, ...) \
267 static co_nmt_boot_state_t *const name = \
268 &(co_nmt_boot_state_t){ __VA_ARGS__ };
269
272 co_nmt_boot_t *boot, const struct timespec *tp);
273
275// clang-format off
276LELY_CO_DEFINE_STATE(co_nmt_boot_wait_state,
277 .on_time = &co_nmt_boot_wait_on_time
279// clang-format on
280
281
283
285// clang-format off
286LELY_CO_DEFINE_STATE(co_nmt_boot_abort_state,
287 .on_enter = &co_nmt_boot_abort_on_enter
289// clang-format on
290
293
296
298// clang-format off
299LELY_CO_DEFINE_STATE(co_nmt_boot_error_state,
300 .on_enter = &co_nmt_boot_error_on_enter,
301 .on_leave = &co_nmt_boot_error_on_leave
303// clang-format on
304
307 co_nmt_boot_t *boot);
308
314 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
315 size_t n);
316
318// clang-format off
319LELY_CO_DEFINE_STATE(co_nmt_boot_chk_device_type_state,
323// clang-format on
324
327 co_nmt_boot_t *boot);
328
334 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
335 size_t n);
336
338// clang-format off
339LELY_CO_DEFINE_STATE(co_nmt_boot_chk_vendor_id_state,
343// clang-format on
344
347 co_nmt_boot_t *boot);
348
354 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
355 size_t n);
356
358// clang-format off
359LELY_CO_DEFINE_STATE(co_nmt_boot_chk_product_code_state,
363// clang-format on
364
367 co_nmt_boot_t *boot);
368
374 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
375 size_t n);
376
378// clang-format off
379LELY_CO_DEFINE_STATE(co_nmt_boot_chk_revision_state,
383// clang-format on
384
387 co_nmt_boot_t *boot);
388
394 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
395 size_t n);
396
398// clang-format off
399LELY_CO_DEFINE_STATE(co_nmt_boot_chk_serial_nr_state,
403// clang-format on
404
407
410 co_nmt_boot_t *boot, const struct timespec *tp);
411
416 co_nmt_boot_t *boot, const struct can_msg *msg);
417
419// clang-format off
420LELY_CO_DEFINE_STATE(co_nmt_boot_chk_node_state,
425// clang-format on
426
429
435 co_unsigned32_t ac, const void *ptr, size_t n);
436
438// clang-format off
439LELY_CO_DEFINE_STATE(co_nmt_boot_chk_sw_state,
440 .on_enter = &co_nmt_boot_chk_sw_on_enter,
441 .on_up_con = &co_nmt_boot_chk_sw_on_up_con
443// clang-format on
444
447
453 co_nmt_boot_t *boot, co_unsigned32_t ac);
454
460 co_unsigned32_t ac, const void *ptr, size_t n);
461
463// clang-format off
464LELY_CO_DEFINE_STATE(co_nmt_boot_stop_prog_state,
469// clang-format on
470
473 co_nmt_boot_t *boot);
474
480 co_nmt_boot_t *boot, co_unsigned32_t ac);
481
483// clang-format off
484LELY_CO_DEFINE_STATE(co_nmt_boot_clear_prog_state,
488// clang-format on
489
492 co_nmt_boot_t *boot);
493
499 co_nmt_boot_t *boot, co_unsigned32_t ac);
500
502// clang-format off
503LELY_CO_DEFINE_STATE(co_nmt_boot_blk_dn_prog_state,
507// clang-format on
508
511
517 co_nmt_boot_t *boot, co_unsigned32_t ac);
518
520// clang-format off
521LELY_CO_DEFINE_STATE(co_nmt_boot_dn_prog_state,
522 .on_enter = &co_nmt_boot_dn_prog_on_enter,
525// clang-format on
526
529 co_nmt_boot_t *boot);
530
533 co_nmt_boot_t *boot, const struct timespec *tp);
534
540 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
541 size_t n);
542
544// clang-format off
545LELY_CO_DEFINE_STATE(co_nmt_boot_wait_flash_state,
550// clang-format on
551
554
560 co_unsigned32_t ac, const void *ptr, size_t n);
561
563// clang-format off
564LELY_CO_DEFINE_STATE(co_nmt_boot_chk_prog_state,
568// clang-format on
569
572 co_nmt_boot_t *boot);
573
579 co_nmt_boot_t *boot, co_unsigned32_t ac);
580
582// clang-format off
583LELY_CO_DEFINE_STATE(co_nmt_boot_start_prog_state,
587// clang-format on
588
591
597 co_nmt_boot_t *boot, const struct timespec *tp);
598
604 co_unsigned32_t ac, const void *ptr, size_t n);
605
610// clang-format off
611LELY_CO_DEFINE_STATE(co_nmt_boot_wait_prog_state,
616// clang-format on
617
620 co_nmt_boot_t *boot);
621
627 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
628 size_t n);
629
633// clang-format off
634LELY_CO_DEFINE_STATE(co_nmt_boot_chk_cfg_date_state,
638// clang-format on
639
645 co_nmt_boot_t *boot, co_unsigned32_t ac, const void *ptr,
646 size_t n);
647
651// clang-format off
652LELY_CO_DEFINE_STATE(co_nmt_boot_chk_cfg_time_state,
655// clang-format on
656
659
665 co_nmt_boot_t *boot, co_unsigned32_t ac);
666
670// clang-format off
671LELY_CO_DEFINE_STATE(co_nmt_boot_up_cfg_state,
672 .on_enter = &co_nmt_boot_up_cfg_on_enter,
673 .on_cfg_con = &co_nmt_boot_up_cfg_on_cfg_con
675// clang-format on
676
679
682 co_nmt_boot_t *boot, const struct timespec *tp);
683
689 co_nmt_boot_t *boot, const struct can_msg *msg);
690
692// clang-format off
693LELY_CO_DEFINE_STATE(co_nmt_boot_ec_state,
694 .on_enter = &co_nmt_boot_ec_on_enter,
695 .on_time = &co_nmt_boot_ec_on_time,
696 .on_recv = &co_nmt_boot_ec_on_recv
698// clang-format on
699
700#undef LELY_CO_DEFINE_STATE
701
714static int co_nmt_boot_dn(co_nmt_boot_t *boot, co_unsigned16_t idx,
715 co_unsigned8_t subidx, co_unsigned16_t type, const void *val);
716
727static int co_nmt_boot_up(co_nmt_boot_t *boot, co_unsigned16_t idx,
728 co_unsigned8_t subidx);
729
743static int co_nmt_boot_chk(co_nmt_boot_t *boot, co_unsigned16_t idx,
744 co_unsigned8_t subidx, const void *ptr, size_t n);
745
751static int co_nmt_boot_send_rtr(co_nmt_boot_t *boot);
752
753void *
754__co_nmt_boot_alloc(void)
755{
756 void *ptr = malloc(sizeof(struct __co_nmt_boot));
757 if (__unlikely(!ptr))
758 set_errc(errno2c(errno));
759 return ptr;
760}
761
762void
763__co_nmt_boot_free(void *ptr)
764{
765 free(ptr);
766}
767
768struct __co_nmt_boot *
769__co_nmt_boot_init(struct __co_nmt_boot *boot, can_net_t *net, co_dev_t *dev,
770 co_nmt_t *nmt)
771{
772 assert(boot);
773 assert(net);
774 assert(dev);
775 assert(nmt);
776
777 int errc = 0;
778
779 boot->net = net;
780 boot->dev = dev;
781 boot->nmt = nmt;
782
783 boot->state = NULL;
784
785 boot->recv = can_recv_create();
786 if (__unlikely(!boot->recv)) {
787 errc = get_errc();
788 goto error_create_recv;
789 }
791
792 boot->timer = can_timer_create();
793 if (__unlikely(!boot->timer)) {
794 errc = get_errc();
795 goto error_create_timer;
796 }
798
799 boot->id = 0;
800
801 boot->timeout = 0;
802 boot->sdo = NULL;
803
804 boot->start = (struct timespec){ 0, 0 };
805 can_net_get_time(boot->net, &boot->start);
806
807 boot->assignment = 0;
808 boot->ms = 0;
809
810 boot->st = 0;
811 boot->es = 0;
812
813 co_sdo_req_init(&boot->req);
814 boot->retry = 0;
815
817 return boot;
818
820error_create_timer:
821 can_recv_destroy(boot->recv);
822error_create_recv:
823 set_errc(errc);
824 return NULL;
825}
826
827void
828__co_nmt_boot_fini(struct __co_nmt_boot *boot)
829{
830 assert(boot);
831
832 co_sdo_req_fini(&boot->req);
833
834 co_csdo_destroy(boot->sdo);
835
837 can_recv_destroy(boot->recv);
838}
839
842{
843 int errc = 0;
844
845 co_nmt_boot_t *boot = __co_nmt_boot_alloc();
846 if (__unlikely(!boot)) {
847 errc = get_errc();
848 goto error_alloc_boot;
849 }
850
851 if (__unlikely(!__co_nmt_boot_init(boot, net, dev, nmt))) {
852 errc = get_errc();
853 goto error_init_boot;
854 }
855
856 return boot;
857
858error_init_boot:
859 __co_nmt_boot_free(boot);
860error_alloc_boot:
861 set_errc(errc);
862 return NULL;
863}
864
865void
867{
868 if (boot) {
869 __co_nmt_boot_fini(boot);
870 __co_nmt_boot_free(boot);
871 }
872}
873
874int
875co_nmt_boot_boot_req(co_nmt_boot_t *boot, co_unsigned8_t id, int timeout,
876 co_csdo_ind_t *dn_ind, co_csdo_ind_t *up_ind, void *data)
877{
878 assert(boot);
879
880 if (__unlikely(!id || id > CO_NUM_NODES)) {
882 return -1;
883 }
884
887 return -1;
888 }
889
890 boot->id = id;
891
892 boot->timeout = timeout;
893 co_csdo_destroy(boot->sdo);
894 boot->sdo = co_csdo_create(boot->net, NULL, boot->id);
895 if (__unlikely(!boot->sdo))
896 return -1;
897 co_csdo_set_timeout(boot->sdo, boot->timeout);
898 co_csdo_set_dn_ind(boot->sdo, dn_ind, data);
899 co_csdo_set_up_ind(boot->sdo, up_ind, data);
900
901 co_nmt_boot_emit_time(boot, NULL);
902
903 return 0;
904}
905
906static int
907co_nmt_boot_recv(const struct can_msg *msg, void *data)
908{
909 assert(msg);
910 co_nmt_boot_t *boot = data;
911 assert(boot);
912
913 co_nmt_boot_emit_recv(boot, msg);
914
915 return 0;
916}
917
918static int
919co_nmt_boot_timer(const struct timespec *tp, void *data)
920{
921 assert(tp);
922 co_nmt_boot_t *boot = data;
923 assert(boot);
924
925 co_nmt_boot_emit_time(boot, tp);
926
927 return 0;
928}
929
930static void
931co_nmt_boot_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
932 co_unsigned32_t ac, void *data)
933{
934 (void)sdo;
935 (void)idx;
936 (void)subidx;
937 co_nmt_boot_t *boot = data;
938 assert(boot);
939
940 co_nmt_boot_emit_dn_con(boot, ac);
941}
942
943static void
944co_nmt_boot_up_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
945 co_unsigned32_t ac, const void *ptr, size_t n, void *data)
946{
947 (void)sdo;
948 (void)idx;
949 (void)subidx;
950 co_nmt_boot_t *boot = data;
951 assert(boot);
952
953 co_nmt_boot_emit_up_con(boot, ac, ptr, n);
954}
955
956static void
957co_nmt_boot_cfg_con(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned32_t ac,
958 void *data)
959{
960 (void)nmt;
961 (void)id;
962 co_nmt_boot_t *boot = data;
963 assert(boot);
964
965 co_nmt_boot_emit_cfg_con(boot, ac);
966}
967
968static void
970{
971 assert(boot);
972
973 while (next) {
974 co_nmt_boot_state_t *prev = boot->state;
975 boot->state = next;
976
977 if (prev && prev->on_leave)
978 prev->on_leave(boot);
979
980 next = next->on_enter ? next->on_enter(boot) : NULL;
981 }
982}
983
984static inline void
986{
987 assert(boot);
988 assert(boot->state);
989 assert(boot->state->on_time);
990
991 co_nmt_boot_enter(boot, boot->state->on_time(boot, tp));
992}
993
994static inline void
996{
997 assert(boot);
998 assert(boot->state);
999 assert(boot->state->on_recv);
1000
1001 co_nmt_boot_enter(boot, boot->state->on_recv(boot, msg));
1002}
1003
1004static inline void
1005co_nmt_boot_emit_dn_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
1006{
1007 assert(boot);
1008 assert(boot->state);
1009 assert(boot->state->on_dn_con);
1010
1011 co_nmt_boot_enter(boot, boot->state->on_dn_con(boot, ac));
1012}
1013
1014static inline void
1015co_nmt_boot_emit_up_con(co_nmt_boot_t *boot, co_unsigned32_t ac,
1016 const void *ptr, size_t n)
1017{
1018 assert(boot);
1019 assert(boot->state);
1020 assert(boot->state->on_up_con);
1021
1022 co_nmt_boot_enter(boot, boot->state->on_up_con(boot, ac, ptr, n));
1023}
1024
1025static inline void
1026co_nmt_boot_emit_cfg_con(co_nmt_boot_t *boot, co_unsigned32_t ac)
1027{
1028 assert(boot);
1029 assert(boot->state);
1030 assert(boot->state->on_cfg_con);
1031
1032 co_nmt_boot_enter(boot, boot->state->on_cfg_con(boot, ac));
1033}
1034
1035static co_nmt_boot_state_t *
1037{
1038 (void)boot;
1039 (void)tp;
1040
1041 boot->st = 0;
1042 boot->es = 0;
1043
1044 // Retrieve the slave assignment for the node.
1045 boot->assignment = co_dev_get_val_u32(boot->dev, 0x1f81, boot->id);
1046
1047 // Find the consumer heartbeat time for the node.
1048 boot->ms = 0;
1049 co_obj_t *obj_1016 = co_dev_find_obj(boot->dev, 0x1016);
1050 if (obj_1016) {
1051 co_unsigned8_t n = co_obj_get_val_u8(obj_1016, 0x00);
1052 for (size_t i = 1; i <= n; i++) {
1053 co_unsigned32_t val =
1054 co_obj_get_val_u32(obj_1016, i & 0xff);
1055 if (((val >> 16) & 0x7f) == boot->id)
1056 boot->ms = val & 0xffff;
1057 }
1058 }
1059
1060 // Abort the 'boot slave' process if the slave is not in the network
1061 // list.
1062 if (!(boot->assignment & 0x01)) {
1063 boot->es = 'A';
1065 }
1066
1067 if (!(boot->assignment & 0x04))
1068 // Skip booting and start the error control service.
1069 return co_nmt_boot_ec_state;
1070
1072}
1073
1074static co_nmt_boot_state_t *
1076{
1077 assert(boot);
1078
1079 can_recv_stop(boot->recv);
1080 can_timer_stop(boot->timer);
1081
1082 // If the node is already operational, end the 'boot slave' process with
1083 // error status L.
1084 if (!boot->es && (boot->st & ~CO_NMT_ST_TOGGLE) == CO_NMT_ST_START)
1085 boot->es = 'L';
1086
1087 // Retry on error status B (see Fig. 4 in CiA 302-2 version 4.1.0).
1088 if (boot->es == 'B') {
1089 int wait = 1;
1090 if (boot->assignment & 0x08) {
1091 // Obtain the time (in milliseconds) the master will
1092 // wait for a mandatory slave to boot.
1093 co_unsigned32_t boot_time = co_dev_get_val_u32(
1094 boot->dev, 0x1f89, 0x00);
1095 // Check if this time has elapsed.
1096 if (boot_time) {
1097 struct timespec now = { 0, 0 };
1098 can_net_get_time(boot->net, &now);
1099 wait = timespec_diff_msec(&now, &boot->start)
1100 < boot_time;
1101 }
1102 }
1103 // If the slave is not mandatory, or the boot time has not yet
1104 // elapsed, wait asynchronously for a while and retry the 'boot
1105 // slave' process.
1106 if (wait) {
1107 can_timer_timeout(boot->timer, boot->net,
1110 }
1111 }
1112
1114}
1115
1116static co_nmt_boot_state_t *
1118{
1119 (void)boot;
1120
1122}
1123
1124static void
1126{
1127 assert(boot);
1128
1129 co_nmt_boot_con(boot->nmt, boot->id, boot->st, boot->es);
1130}
1131
1132static co_nmt_boot_state_t *
1134{
1135 assert(boot);
1136
1137 boot->es = 'B';
1138
1139 // The device type check may follow an NMT 'reset communication'
1140 // command, in which case we may have to give the slave some time to
1141 // complete the state change. Start the first SDO request by simulating
1142 // a timeout.
1145 boot, CO_SDO_AC_TIMEOUT, NULL, 0);
1146}
1147
1148static co_nmt_boot_state_t *
1150 const void *ptr, size_t n)
1151{
1152 assert(boot);
1153
1154 // Retry the SDO request on timeout (this includes the first attempt).
1155 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1156 // Read the device type of the slave (object 1000).
1157 if (__unlikely(co_nmt_boot_up(boot, 0x1000, 0x00) == -1))
1159 return NULL;
1160 } else if (__unlikely(ac)) {
1161 diag(DIAG_ERROR, 0,
1162 "SDO abort code %08" PRIX32
1163 " received on upload request of object 1000 (Device type) to node %02X: %s",
1164 ac, boot->id, co_sdo_ac2str(ac));
1166 }
1167
1168 // If the expected device type (sub-object 1F84:ID) is 0, skip the check
1169 // and proceed with the vendor ID.
1170 co_unsigned32_t device_type =
1171 co_dev_get_val_u32(boot->dev, 0x1f84, boot->id);
1172 // clang-format off
1173 if (__unlikely(device_type && !co_nmt_boot_chk(boot, 0x1f84, boot->id,
1174 ptr, n))) {
1175 // clang-format on
1176 boot->es = 'C';
1178 }
1179
1181}
1182
1183static co_nmt_boot_state_t *
1185{
1186 assert(boot);
1187
1188 // If the expected vendor ID (sub-object 1F85:ID) is 0, skip the check
1189 // and proceed with the product code.
1190 co_unsigned32_t vendor_id =
1191 co_dev_get_val_u32(boot->dev, 0x1f85, boot->id);
1192 if (!vendor_id)
1194
1195 boot->es = 'D';
1196
1197 // Read the vendor ID of the slave (sub-object 1018:01).
1198 if (__unlikely(co_nmt_boot_up(boot, 0x1018, 0x01) == -1))
1200
1201 return NULL;
1202}
1203
1204static co_nmt_boot_state_t *
1206 const void *ptr, size_t n)
1207{
1208 assert(boot);
1209
1210 if (__unlikely(ac))
1211 diag(DIAG_ERROR, 0,
1212 "SDO abort code %08" PRIX32
1213 " received on upload request of sub-object 1018:01 (Vendor-ID) to node %02X: %s",
1214 ac, boot->id, co_sdo_ac2str(ac));
1215
1216 if (__unlikely(ac || !co_nmt_boot_chk(boot, 0x1f85, boot->id, ptr, n)))
1218
1220}
1221
1222static co_nmt_boot_state_t *
1224{
1225 assert(boot);
1226
1227 // If the expected product code (sub-object 1F86:ID) is 0, skip the
1228 // check and proceed with the revision number.
1229 co_unsigned32_t product_code =
1230 co_dev_get_val_u32(boot->dev, 0x1f86, boot->id);
1231 if (!product_code)
1233
1234 boot->es = 'M';
1235
1236 // Read the product code of the slave (sub-object 1018:02).
1237 if (__unlikely(co_nmt_boot_up(boot, 0x1018, 0x02) == -1))
1239
1240 return NULL;
1241}
1242
1243static co_nmt_boot_state_t *
1245 const void *ptr, size_t n)
1246{
1247 assert(boot);
1248
1249 if (__unlikely(ac))
1250 diag(DIAG_ERROR, 0,
1251 "SDO abort code %08" PRIX32
1252 " received on upload request of sub-object 1018:02 (Product code) to node %02X: %s",
1253 ac, boot->id, co_sdo_ac2str(ac));
1254
1255 if (__unlikely(ac || !co_nmt_boot_chk(boot, 0x1f86, boot->id, ptr, n)))
1257
1259}
1260
1261static co_nmt_boot_state_t *
1263{
1264 assert(boot);
1265
1266 // If the expected revision number (sub-object 1F87:ID) is 0, skip the
1267 // check and proceed with the serial number.
1268 co_unsigned32_t revision =
1269 co_dev_get_val_u32(boot->dev, 0x1f87, boot->id);
1270 if (!revision)
1272
1273 boot->es = 'N';
1274
1275 // Read the revision number of the slave (sub-object 1018:03).
1276 if (__unlikely(co_nmt_boot_up(boot, 0x1018, 0x03) == -1))
1278
1279 return NULL;
1280}
1281
1282static co_nmt_boot_state_t *
1284 const void *ptr, size_t n)
1285{
1286 assert(boot);
1287
1288 if (__unlikely(ac))
1289 diag(DIAG_ERROR, 0,
1290 "SDO abort code %08" PRIX32
1291 " received on upload request of sub-object 1018:03 (Revision number) to node %02X: %s",
1292 ac, boot->id, co_sdo_ac2str(ac));
1293
1294 if (__unlikely(ac || !co_nmt_boot_chk(boot, 0x1f87, boot->id, ptr, n)))
1296
1298}
1299
1300static co_nmt_boot_state_t *
1302{
1303 assert(boot);
1304
1305 // If the expected serial number (sub-object 1F88:ID) is 0, skip the
1306 // check and proceed to 'check node state'.
1307 co_unsigned32_t serial_nr =
1308 co_dev_get_val_u32(boot->dev, 0x1f88, boot->id);
1309 if (!serial_nr)
1311
1312 boot->es = 'O';
1313
1314 // Read the serial number of the slave (sub-object 1018:04).
1315 if (__unlikely(co_nmt_boot_up(boot, 0x1018, 0x04) == -1))
1317
1318 return NULL;
1319}
1320
1321static co_nmt_boot_state_t *
1323 const void *ptr, size_t n)
1324{
1325 assert(boot);
1326
1327 if (__unlikely(ac))
1328 diag(DIAG_ERROR, 0,
1329 "SDO abort code %08" PRIX32
1330 " received on upload request of sub-object 1018:04 (Serial number) to node %02X: %s",
1331 ac, boot->id, co_sdo_ac2str(ac));
1332
1333 if (__unlikely(ac || !co_nmt_boot_chk(boot, 0x1f88, boot->id, ptr, n)))
1335
1337}
1338
1339static co_nmt_boot_state_t *
1341{
1342 assert(boot);
1343
1344 // If the keep-alive bit is set, check the node state.
1345 if (boot->assignment & 0x10) {
1346 int ms;
1347 if (boot->ms) {
1348 ms = boot->ms;
1349 boot->es = 'E';
1350 } else {
1352 boot->es = 'F';
1353 // If we're not a heartbeat consumer, start node
1354 // guarding by sending the first RTR.
1356 }
1357
1358 // Start the CAN frame receiver for the heartbeat or node guard
1359 // message.
1360 can_recv_start(boot->recv, boot->net, CO_NMT_EC_CANID(boot->id),
1361 0);
1362 // Start the CAN timer in case we do not receive a heartbeat
1363 // indication or a node guard confirmation.
1364 can_timer_timeout(boot->timer, boot->net, ms);
1365
1366 return NULL;
1367 }
1368
1370}
1371
1372static co_nmt_boot_state_t *
1374{
1375 (void)boot;
1376 (void)tp;
1377
1379}
1380
1381static co_nmt_boot_state_t *
1383{
1384 assert(boot);
1385
1386 can_recv_stop(boot->recv);
1387 can_timer_stop(boot->timer);
1388
1389 assert(msg);
1390 assert(msg->len >= 1);
1391 boot->st = msg->data[0];
1392
1393 if ((boot->st & ~CO_NMT_ST_TOGGLE) == CO_NMT_ST_START) {
1394 // If the node is already operational, skip the 'check and
1395 // update software version' and 'check configuration' steps and
1396 // proceed immediately to 'start error control service'.
1397 return co_nmt_boot_ec_state;
1398 } else {
1399 boot->st = 0;
1400 // If the node is not operational, send the NMT 'reset
1401 // communication' command and proceed as if the keep-alive bit
1402 // was not set.
1405 }
1406}
1407
1408static co_nmt_boot_state_t *
1410{
1411 assert(boot);
1412
1413 if (boot->assignment & 0x20) {
1414 boot->es = 'G';
1415
1416 // Abort if the expected program software identification
1417 // (sub-object 1F55:ID) is 0.
1418 co_unsigned32_t sw_id =
1419 co_dev_get_val_u32(boot->dev, 0x1f55, boot->id);
1420 if (!sw_id)
1422
1423 // The software version check may follow an NMT 'reset
1424 // communication' command, in which case we may have to give the
1425 // slave some time to complete the state change. Start the first
1426 // SDO request by simulating a timeout.
1429 boot, CO_SDO_AC_TIMEOUT, NULL, 0);
1430 }
1431
1432 // Continue with the 'check configuration' step if the software version
1433 // check is not necessary.
1435}
1436
1437static co_nmt_boot_state_t *
1439 const void *ptr, size_t n)
1440{
1441 assert(boot);
1442
1443 // Retry the SDO request on timeout (this includes the first attempt).
1444 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1445 // Read the program software identification of the slave
1446 // (sub-object 1F56:01).
1447 if (__unlikely(co_nmt_boot_up(boot, 0x1f56, 0x01) == -1))
1449 return NULL;
1450 } else if (__unlikely(ac)) {
1451 diag(DIAG_ERROR, 0,
1452 "SDO abort code %08" PRIX32
1453 " received on upload request of sub-object 1F56:01 (Program software identification) to node %02X: %s",
1454 ac, boot->id, co_sdo_ac2str(ac));
1456 }
1457
1458 // If the program software identification matches the expected value,
1459 // proceed to 'check configuration'.
1460 if (co_nmt_boot_chk(boot, 0x1f55, boot->id, ptr, n))
1462
1463 // Do not update the software if software update (bit 6) is not allowed
1464 // or if the keep-alive bit (bit 4) is set.
1465 if ((boot->assignment & 0x50) != 0x40) {
1466 boot->es = 'H';
1468 }
1469
1470 boot->es = 'I';
1471
1473}
1474
1475static co_nmt_boot_state_t *
1477{
1478 assert(boot);
1479
1480 // Read the program control of the slave (sub-object 1F51:01).
1481 if (__unlikely(co_nmt_boot_up(boot, 0x1f51, 0x01) == -1))
1483
1484 return NULL;
1485}
1486
1487static co_nmt_boot_state_t *
1489{
1490 assert(boot);
1491
1492 // The download SDO request may be unconfirmed on some devices since it
1493 // stops the program on the slave (and may cause a restart of the
1494 // bootloader). We therefore ignore timeouts.
1495 if (__unlikely(ac && ac != CO_SDO_AC_TIMEOUT)) {
1496 diag(DIAG_ERROR, 0,
1497 "SDO abort code %08" PRIX32
1498 " received on download request of sub-object 1F51:01 (Program control) to node %02X: %s",
1499 ac, boot->id, co_sdo_ac2str(ac));
1501 }
1502
1504}
1505
1506static co_nmt_boot_state_t *
1508 const void *ptr, size_t n)
1509{
1510 assert(boot);
1511
1512 // If the value is already 0 (Program stopped), do not write a 0 (Stop
1513 // program), but skip to the 'clear program' state.
1514 co_unsigned8_t val = 0;
1515 // clang-format off
1516 if (!ac && co_val_read(CO_DEFTYPE_UNSIGNED8, &val, ptr,
1517 (const uint8_t *)ptr + n) && !val)
1518 // clang-format on
1520
1521 // Write a 0 (Stop program) to the program control of the slave
1522 // (sub-object 1F51:01).
1523 // clang-format off
1524 if (__unlikely(co_nmt_boot_dn(boot, 0x1f51, 0x01, CO_DEFTYPE_UNSIGNED8,
1525 &(co_unsigned8_t){ 0 }) == -1))
1526 // clang-format on
1528
1529 return NULL;
1530}
1531
1532static co_nmt_boot_state_t *
1534{
1535 assert(boot);
1536
1537 // The 'clear program' command follows the 'stop program' command, which
1538 // may have triggered a reboot of the slave. In that case we may have to
1539 // give the slave some time to finish booting. Start the first SDO
1540 // request by simulating a timeout.
1543}
1544
1545static co_nmt_boot_state_t *
1547{
1548 assert(boot);
1549
1550 // Retry the SDO request on timeout.
1551 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1552 // Write a 3 (Clear program) to the program control of the slave
1553 // (sub-object 1F51:01).
1554 // clang-format off
1555 if (__unlikely(co_nmt_boot_dn(boot, 0x1f51, 0x01,
1556 CO_DEFTYPE_UNSIGNED8, &(co_unsigned8_t){ 3 })
1557 == -1))
1558 // clang-format on
1560 return NULL;
1561 } else if (__unlikely(ac)) {
1562 diag(DIAG_ERROR, 0,
1563 "SDO abort code %08" PRIX32
1564 " received on download request of sub-object 1F51:01 (Program control) to node %02X: %s",
1565 ac, boot->id, co_sdo_ac2str(ac));
1567 }
1568
1570}
1571
1572static co_nmt_boot_state_t *
1574{
1575 assert(boot);
1576
1577 co_sub_t *sub = co_dev_find_sub(boot->dev, 0x1f58, boot->id);
1578 if (__unlikely(!sub))
1580
1581 // Upload the program data.
1582 struct co_sdo_req *req = &boot->req;
1583 co_sdo_req_clear(req);
1584 co_unsigned32_t ac = co_sub_up_ind(sub, req);
1585 if (__unlikely(ac || !co_sdo_req_first(req) || !co_sdo_req_last(req))) {
1586 if (ac)
1587 diag(DIAG_ERROR, 0,
1588 "SDO abort code %08" PRIX32
1589 " on upload request of object 1F58:%02X (Program data): %s",
1590 ac, boot->id, co_sdo_ac2str(ac));
1592 }
1593
1594 // The 'clear program' step may take some time to complete, causing an
1595 // immediate 'download program' to generate a timeout. Start the first
1596 // attempt by simulating a timeout.
1599}
1600
1601static co_nmt_boot_state_t *
1603{
1604 (void)boot;
1605
1606 // Retry the SDO request on timeout (this includes the first attempt).
1607 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1608 struct co_sdo_req *req = &boot->req;
1609 // Write the program data (sub-object 1F58:ID) to the program
1610 // data of the slave (sub-object 1F50:01) using SDO block
1611 // transfer.
1612 // clang-format off
1613 if (__unlikely(co_csdo_blk_dn_req(boot->sdo, 0x1f50, 0x01,
1614 req->buf, req->size, &co_nmt_boot_dn_con, boot)
1615 == -1))
1616 // clang-format on
1618 return NULL;
1619 } else if (__unlikely(ac)) {
1620 // If SDO block transfer is not supported, fall back to SDO
1621 // segmented transfer.
1623 }
1624
1626}
1627
1628static co_nmt_boot_state_t *
1630{
1631 assert(boot);
1632
1633 // If SDO block transfer is not supported, we may still have to wait for
1634 // the 'clear program' step to complete before successfully doing a
1635 // segmented SDO transfer. Start the first attempt by simulating a
1636 // timeout.
1639}
1640
1641static co_nmt_boot_state_t *
1643{
1644 assert(boot);
1645
1646 // Retry the SDO request on timeout (this includes the first attempt).
1647 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1648 struct co_sdo_req *req = &boot->req;
1649 // Write the program data (sub-object 1F58:ID) to the program
1650 // data of the slave (sub-object 1F50:01) using SDO segmented
1651 // transfer.
1652 // clang-format off
1653 if (__unlikely(co_csdo_dn_req(boot->sdo, 0x1f50, 0x01, req->buf,
1654 req->size, &co_nmt_boot_dn_con,
1655 boot) == -1))
1656 // clang-format on
1658 return NULL;
1659 } else if (__unlikely(ac)) {
1660 diag(DIAG_ERROR, 0,
1661 "SDO abort code %08" PRIX32
1662 " received on download request of sub-object 1F50:01 (Program data) to node %02X: %s",
1663 ac, boot->id, co_sdo_ac2str(ac));
1665 }
1666
1668}
1669
1670static co_nmt_boot_state_t *
1672{
1673 assert(boot);
1674
1675 // Wait for a while before checking the flash status indication.
1678
1679 return NULL;
1680}
1681
1682static co_nmt_boot_state_t *
1684{
1685 assert(boot);
1686 (void)tp;
1687
1688 // Read the flash status indication of the slave (sub-object 1F57:01).
1689 if (__unlikely(co_nmt_boot_up(boot, 0x1f57, 0x01) == -1))
1691
1692 return NULL;
1693}
1694
1695static co_nmt_boot_state_t *
1697 const void *ptr, size_t n)
1698{
1699 assert(boot);
1700
1701 if (__unlikely(ac))
1702 diag(DIAG_ERROR, 0,
1703 "SDO abort code %08" PRIX32
1704 " received on upload request of sub-object 1F57:01 (Flash status indication) to node %02X: %s",
1705 ac, boot->id, co_sdo_ac2str(ac));
1706
1707 // If the flash status indication is not valid, try again.
1708 co_unsigned32_t val = 0;
1709 // clang-format off
1711 (const uint8_t *)ptr + n) || (val & 0x01)))
1712 // clang-format on
1714
1715 co_unsigned8_t st = (val >> 1) & 0x7f;
1716 switch (st) {
1717 case 0: return co_nmt_boot_chk_prog_state;
1718 case 1:
1719 diag(DIAG_ERROR, 0,
1720 "flash status identification %d: No valid program available",
1721 st);
1722 break;
1723 case 2:
1724 diag(DIAG_ERROR, 0,
1725 "flash status identification %d: Data format unknown",
1726 st);
1727 break;
1728 case 3:
1729 diag(DIAG_ERROR, 0,
1730 "flash status identification %d: Data format error or data CRC error",
1731 st);
1732 break;
1733 case 4:
1734 diag(DIAG_ERROR, 0,
1735 "flash status identification %d: Flash not cleared before write",
1736 st);
1737 break;
1738 case 5:
1739 diag(DIAG_ERROR, 0,
1740 "flash status identification %d: Flash write error",
1741 st);
1742 break;
1743 case 6:
1744 diag(DIAG_ERROR, 0,
1745 "flash status identification %d: General address error",
1746 st);
1747 break;
1748 case 7:
1749 diag(DIAG_ERROR, 0,
1750 "flash status identification %d: Flash secured (= write access currently forbidden)",
1751 st);
1752 break;
1753 case 63:
1754 diag(DIAG_ERROR, 0,
1755 "flash status identification %d: Unspecified error",
1756 st);
1757 break;
1758 default:
1759 if (st > 63)
1760 diag(DIAG_ERROR, 0,
1761 "flash status identification %d: Manufacturer-specific error: 0x%08" PRIX32
1762 "",
1763 st, (val >> 16) & 0xffff);
1764 break;
1765 }
1766
1768}
1769
1770static co_nmt_boot_state_t *
1772{
1773 assert(boot);
1774
1775 // Read the program software identification of the slave (sub-object
1776 // 1F56:01).
1777 if (__unlikely(co_nmt_boot_up(boot, 0x1f56, 0x01) == -1))
1779
1780 return NULL;
1781}
1782
1783static co_nmt_boot_state_t *
1785 const void *ptr, size_t n)
1786{
1787 assert(boot);
1788
1789 if (__unlikely(ac))
1790 diag(DIAG_ERROR, 0,
1791 "SDO abort code %08" PRIX32
1792 " received on upload request of sub-object 1F56:01 (Program software identification) to node %02X: %s",
1793 ac, boot->id, co_sdo_ac2str(ac));
1794
1795 if (__unlikely(ac || !co_nmt_boot_chk(boot, 0x1f55, boot->id, ptr, n)))
1797
1799}
1800
1801static co_nmt_boot_state_t *
1803{
1804 assert(boot);
1805
1806 // Write a 1 (Start program) to the program control of the slave
1807 // (sub-object 1F51:01).
1808 // clang-format off
1809 if (__unlikely(co_nmt_boot_dn(boot, 0x1f51, 0x01, CO_DEFTYPE_UNSIGNED8,
1810 &(co_unsigned8_t){ 1 }) == -1))
1811 // clang-format on
1813
1814 return NULL;
1815}
1816
1817static co_nmt_boot_state_t *
1819{
1820 assert(boot);
1821
1822 if (__unlikely(ac)) {
1823 diag(DIAG_ERROR, 0,
1824 "SDO abort code %08" PRIX32
1825 " received on download request of sub-object 1F51:01 (Program control) to node %02X: %s",
1826 ac, boot->id, co_sdo_ac2str(ac));
1828 }
1829
1831}
1832
1833static co_nmt_boot_state_t *
1835{
1836 assert(boot);
1837
1838 // Wait for a while before checking the program control.
1841
1842 return NULL;
1843}
1844
1845static co_nmt_boot_state_t *
1847{
1848 assert(boot);
1849 (void)tp;
1850
1851 // The 'start program' step may take some time to complete, causing an
1852 // immediate SDO upload request to generate a timeout. Start the first
1853 // attempt by simulating a timeout.
1856 boot, CO_SDO_AC_TIMEOUT, NULL, 0);
1857
1858 return NULL;
1859}
1860
1861static co_nmt_boot_state_t *
1863 const void *ptr, size_t n)
1864{
1865 assert(boot);
1866
1867 // Retry the SDO request on timeout (this includes the first attempt).
1868 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1869 // Read the program control of the slave (sub-object 1F51:01).
1870 if (__unlikely(co_nmt_boot_up(boot, 0x1f51, 0x01) == -1))
1872 return NULL;
1873 } else if (__unlikely(ac)) {
1874 diag(DIAG_ERROR, 0,
1875 "SDO abort code %08" PRIX32
1876 " received on upload request of sub-object 1F51:01 (Program control) to node %02X: %s",
1877 ac, boot->id, co_sdo_ac2str(ac));
1879 }
1880
1881 // If the program control differs from 'Program started', try again.
1882 co_unsigned8_t val = 0;
1883 // clang-format off
1885 (const uint8_t *)ptr + n) || val != 1))
1886 // clang-format on
1888
1890}
1891
1892static co_nmt_boot_state_t *
1894{
1895 assert(boot);
1896
1897 boot->es = 'J';
1898
1899 // If the expected configuration date (sub-object 1F26:ID) or time
1900 // (sub-object 1F27:ID) are not configured, proceed to 'update
1901 // configuration'.
1902 co_unsigned32_t cfg_date =
1903 co_dev_get_val_u32(boot->dev, 0x1f26, boot->id);
1904 co_unsigned32_t cfg_time =
1905 co_dev_get_val_u32(boot->dev, 0x1f27, boot->id);
1906 if (!cfg_date || !cfg_time)
1908
1909 // The configuration check may follow an NMT 'reset communication'
1910 // command (if the 'check software version' step was skipped), in which
1911 // case we may have to give the slave some time to complete the state
1912 // change. Start the first SDO request by simulating a timeout.
1915 boot, CO_SDO_AC_TIMEOUT, NULL, 0);
1916}
1917
1918static co_nmt_boot_state_t *
1920 const void *ptr, size_t n)
1921{
1922 assert(boot);
1923
1924 // Retry the SDO request on timeout (this includes the first attempt).
1925 if (ac == CO_SDO_AC_TIMEOUT && boot->retry--) {
1926 // Read the configuration date of the slave (sub-object
1927 // 1020:01).
1928 if (__unlikely(co_nmt_boot_up(boot, 0x1020, 0x01) == -1))
1930 return NULL;
1931 } else if (__unlikely(ac)) {
1932 diag(DIAG_ERROR, 0,
1933 "SDO abort code %08" PRIX32
1934 " received on upload request of sub-object 1020:01 (Configuration date) to node %02X: %s",
1935 ac, boot->id, co_sdo_ac2str(ac));
1936 }
1937
1938 // If the configuration date does not match the expected value, skip
1939 // checking the time and proceed to 'update configuration'.
1940 if (__unlikely(ac || !co_nmt_boot_chk(boot, 0x1f26, boot->id, ptr, n)))
1942
1943 // Read the configuration time of the slave (sub-object 1020:02).
1944 if (__unlikely(co_nmt_boot_up(boot, 0x1020, 0x02) == -1))
1946
1948}
1949
1950static co_nmt_boot_state_t *
1952 const void *ptr, size_t n)
1953{
1954 assert(boot);
1955
1956 if (__unlikely(ac))
1957 diag(DIAG_ERROR, 0,
1958 "SDO abort code %08" PRIX32
1959 " received on upload request of sub-object 1020:02 (Configuration time) to node %02X: %s",
1960 ac, boot->id, co_sdo_ac2str(ac));
1961
1962 // If the configuration time does not match the expected value, proceed
1963 // to 'update configuration'.
1964 if (__unlikely(ac || !co_nmt_boot_chk(boot, 0x1f27, boot->id, ptr, n)))
1966
1967 return co_nmt_boot_ec_state;
1968}
1969
1970static co_nmt_boot_state_t *
1972{
1973 assert(boot);
1974
1975 boot->es = 'J';
1976
1977 // clang-format off
1978 if (__unlikely(co_nmt_cfg_req(boot->nmt, boot->id, boot->timeout,
1979 &co_nmt_boot_cfg_con, boot) == -1))
1980 // clang-format on
1982
1983 return NULL;
1984}
1985
1986static co_nmt_boot_state_t *
1988{
1989 assert(boot);
1990
1991 if (__unlikely(ac)) {
1992 diag(DIAG_ERROR, 0,
1993 "SDO abort code %08" PRIX32
1994 " received while updating the configuration of node %02X: %s",
1995 ac, boot->id, co_sdo_ac2str(ac));
1997 }
1998
1999 return co_nmt_boot_ec_state;
2000}
2001
2002static co_nmt_boot_state_t *
2004{
2005 assert(boot);
2006
2007 if (boot->ms) {
2008 boot->es = 'K';
2009 // Start the CAN frame receiver for heartbeat messages.
2010 can_recv_start(boot->recv, boot->net, CO_NMT_EC_CANID(boot->id),
2011 0);
2012 // Wait for the first heartbeat indication.
2013 can_timer_timeout(boot->timer, boot->net, boot->ms);
2014 return NULL;
2015 } else if (boot->assignment & 0x01) {
2016 // If the guard time is non-zero, start node guarding by sending
2017 // the first RTR, but do not wait for the response.
2018 co_unsigned16_t gt = (boot->assignment >> 16) & 0xffff;
2019 if (gt)
2021 }
2022
2023 boot->es = 0;
2025}
2026
2027static co_nmt_boot_state_t *
2029{
2030 (void)boot;
2031 (void)tp;
2032
2034}
2035
2036static co_nmt_boot_state_t *
2038{
2039 assert(boot);
2040 assert(msg);
2041
2042 if (msg->len >= 1) {
2043 co_unsigned8_t st = msg->data[0];
2044 // Do not consider a boot-up message to be a heartbeat message.
2045 if (st == CO_NMT_ST_BOOTUP)
2046 return NULL;
2047 boot->st = st;
2048 boot->es = 0;
2049 }
2050
2052}
2053
2054static int
2055co_nmt_boot_dn(co_nmt_boot_t *boot, co_unsigned16_t idx, co_unsigned8_t subidx,
2056 co_unsigned16_t type, const void *val)
2057{
2058 assert(boot);
2059
2060 return co_csdo_dn_val_req(boot->sdo, idx, subidx, type, val,
2061 &co_nmt_boot_dn_con, boot);
2062}
2063
2064static int
2065co_nmt_boot_up(co_nmt_boot_t *boot, co_unsigned16_t idx, co_unsigned8_t subidx)
2066{
2067 assert(boot);
2068
2069 return co_csdo_up_req(
2070 boot->sdo, idx, subidx, &co_nmt_boot_up_con, boot);
2071}
2072
2073static int
2074co_nmt_boot_chk(co_nmt_boot_t *boot, co_unsigned16_t idx, co_unsigned8_t subidx,
2075 const void *ptr, size_t n)
2076{
2077 assert(boot);
2078
2079 co_sub_t *sub = co_dev_find_sub(boot->dev, idx, subidx);
2080 if (__unlikely(!sub))
2081 return 0;
2082 co_unsigned16_t type = co_sub_get_type(sub);
2083
2084 union co_val val;
2085 if (__unlikely(!co_val_read(type, &val, ptr, (const uint8_t *)ptr + n)))
2086 return 0;
2087
2088 int eq = !co_val_cmp(type, &val, co_sub_get_val(sub));
2089 co_val_fini(type, &val);
2090 return eq;
2091}
2092
2093static int
2095{
2096 assert(boot);
2097
2098 struct can_msg msg = CAN_MSG_INIT;
2099 msg.id = CO_NMT_EC_CANID(boot->id);
2100 msg.flags |= CAN_FLAG_RTR;
2101
2102 return can_net_send(boot->net, &msg);
2103}
2104
2105#endif // !LELY_NO_CO_MASTER
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:1080
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:1011
void co_csdo_set_timeout(co_csdo_t *sdo, int timeout)
Sets the timeout of a Client-SDO.
Definition: csdo.c:944
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:1099
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:986
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:966
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:867
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:1036
void co_csdo_destroy(co_csdo_t *sdo)
Destroys a CANopen Client-SDO service.
Definition: csdo.c:894
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
This header file is part of the utilities library; it contains the diagnostic declarations.
@ DIAG_ERROR
An error.
Definition: diag.h:49
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:129
@ ERRNUM_INPROGRESS
Operation in progress.
Definition: errnum.h:125
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
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:613
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:890
co_unsigned16_t co_sub_get_type(const co_sub_t *sub)
Returns the data type of a CANopen sub-object.
Definition: obj.c:508
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
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:346
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
#define CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames).
Definition: msg.h:47
#define CAN_MSG_INIT
The static initializer for can_msg.
Definition: msg.h:114
void can_timer_stop(can_timer_t *timer)
Stops a CAN timer and unregisters it with a network interface.
Definition: net.c:468
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
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition: net.c:382
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
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
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
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
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition: net.c:562
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
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
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition: net.c:537
void can_timer_destroy(can_timer_t *timer)
Destroys a CAN timer.
Definition: net.c:407
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:1865
#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:1588
#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:1455
#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_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:1987
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:402
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:468
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:654
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:1005
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:1117
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:1262
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:1834
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:1340
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:549
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:2028
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:1802
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:1784
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:506
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:2074
static co_nmt_boot_state_t *const co_nmt_boot_up_cfg_state
The 'update configuration' state (see Fig.
Definition: nmt_boot.c:674
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:2037
#define LELY_CO_NMT_BOOT_RTR_TIMEOUT
The timeout (in milliseconds) after sending a node guarding RTR.
Definition: nmt_boot.c:51
static void co_nmt_boot_error_on_leave(co_nmt_boot_t *boot)
The exit function of the 'error' state.
Definition: nmt_boot.c:1125
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:1026
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:1546
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:1573
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:1893
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:1133
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:1951
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:1671
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:1862
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:969
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:944
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:1642
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:615
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:1036
void co_nmt_boot_destroy(co_nmt_boot_t *boot)
Destroys a CANopen NMT 'boot slave' service.
Definition: nmt_boot.c:866
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:1322
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:957
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:1533
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:1507
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:362
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:1771
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:1438
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:1919
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:2003
#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:59
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:424
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:1602
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:931
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:1223
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:919
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:985
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:382
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:1382
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:697
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:1205
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:1488
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:875
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:342
#define LELY_CO_NMT_BOOT_WAIT_TIMEOUT
The timeout (in milliseconds) before trying to boot the slave again.
Definition: nmt_boot.c:41
static int co_nmt_boot_send_rtr(co_nmt_boot_t *boot)
Sends a node guarding RTR to the slave.
Definition: nmt_boot.c:2094
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:1818
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:2055
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:586
static co_nmt_boot_state_t *const co_nmt_boot_wait_state
The 'wait asynchronously' state.
Definition: nmt_boot.c:278
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:567
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:1683
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:524
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:1149
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:1629
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:841
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:2065
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:907
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:1301
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:1015
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:1184
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:1476
static co_nmt_boot_state_t *const co_nmt_boot_error_state
The 'error' state.
Definition: nmt_boot.c:302
#define LELY_CO_NMT_BOOT_SDO_RETRY
The number of times an SDO request is retried after a timeout.
Definition: nmt_boot.c:46
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:1373
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:322
static co_nmt_boot_state_t *const co_nmt_boot_abort_state
The 'abort' state.
Definition: nmt_boot.c:288
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:637
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:1244
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:442
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:1283
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:1409
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:487
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:1971
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:1846
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:1075
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:1696
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:995
This is the internal header file of the NMT 'boot slave' declarations.
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:99
A CAN timer.
Definition: net.c:63
A CANopen Client-SDO.
Definition: csdo.c:45
A CANopen device.
Definition: dev.c:38
A CANopen NMT 'boot slave' state.
Definition: nmt_boot.c:203
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:205
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:249
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:236
void(* on_leave)(co_nmt_boot_t *boot)
A pointer to the function invoked when the current state is left.
Definition: nmt_boot.c:263
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:260
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:214
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:225
A CANopen NMT 'boot slave' service.
Definition: nmt_boot.c:67
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: nmt_boot.c:77
struct co_sdo_req req
The CANopen SDO upload request used for reading sub-objects.
Definition: nmt_boot.c:93
can_timer_t * timer
A pointer to the CAN timer.
Definition: nmt_boot.c:79
co_nmt_t * nmt
A pointer to an NMT master service.
Definition: nmt_boot.c:73
can_net_t * net
A pointer to a CAN network interface.
Definition: nmt_boot.c:69
co_nmt_boot_state_t * state
A pointer to the current state.
Definition: nmt_boot.c:75
co_unsigned32_t assignment
The NMT slave assignment (object 1F81).
Definition: nmt_boot.c:89
co_unsigned16_t ms
The consumer heartbeat time (in milliseconds).
Definition: nmt_boot.c:91
int retry
The number of SDO retries remaining.
Definition: nmt_boot.c:95
co_csdo_t * sdo
A pointer to the Client-SDO used to access slave objects.
Definition: nmt_boot.c:85
co_unsigned8_t id
The node-ID.
Definition: nmt_boot.c:81
co_dev_t * dev
A pointer to a CANopen device.
Definition: nmt_boot.c:71
char es
The error status.
Definition: nmt_boot.c:99
struct timespec start
The time at which the 'boot slave' request was received.
Definition: nmt_boot.c:87
int timeout
The SDO timeout (in milliseconds).
Definition: nmt_boot.c:83
co_unsigned8_t st
The state of the node (including the toggle bit).
Definition: nmt_boot.c:97
A CANopen NMT master/slave service.
Definition: nmt.c:104
A CANopen object.
Definition: obj.h:32
A CANopen sub-object.
Definition: obj.h:54
A CAN or CAN FD format frame.
Definition: msg.h:88
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition: msg.h:103
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition: msg.h:90
uint_least8_t flags
The flags (any combination of CAN_FLAG_IDE, CAN_FLAG_RTR, CAN_FLAG_EDL, CAN_FLAG_BRS and CAN_FLAG_ESI...
Definition: msg.h:95
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:101
A CANopen SDO upload/download request.
Definition: sdo.h:178
size_t size
The total size (in bytes) of the value to be uploaded/downloaded.
Definition: sdo.h:184
const void * buf
A pointer to the next bytes to be uploaded/downloaded.
Definition: sdo.h:186
A time type with nanosecond resolution.
Definition: time.h:83
#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:163
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:203
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 uint8_t *begin, const uint8_t *end)
Reads a value of the specified data type from a memory buffer.
Definition: val.c:470
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:386
void co_val_fini(co_unsigned16_t type, void *val)
Finalizes a value of the specified data type.
Definition: val.c:273