Lely core libraries 1.9.2
nmt_boot.c
Go to the documentation of this file.
1
23
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
struct __co_csdo co_csdo_t
An opaque CANopen Client-SDO service type.
Definition co.h:79
struct __co_nmt co_nmt_t
An opaque CANopen NMT master/slave service type.
Definition co.h:145
struct __co_sub co_sub_t
An opaque CANopen sub-object type.
Definition co.h:57
struct __co_obj co_obj_t
An opaque CANopen object type.
Definition co.h:46
struct __co_dev co_dev_t
An opaque CANopen device type.
Definition co.h:35
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
struct __can_net can_net_t
An opaque CAN network interface type.
Definition net.h:31
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
struct __can_timer can_timer_t
An opaque CAN timer type.
Definition net.h:37
struct __can_recv can_recv_t
An opaque CAN frame receiver type.
Definition net.h:43
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
const struct __co_nmt_boot_state co_nmt_boot_state_t
An opaque CANopen NMT 'boot slave' state type.
Definition nmt_boot.c:64
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.
struct __co_nmt_boot co_nmt_boot_t
An opaque CANopen NMT 'boot slave' service type.
Definition nmt_boot.h:33
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 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 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