Lely core libraries  2.2.5
nmt_cfg.c
Go to the documentation of this file.
1 
24 #include "co.h"
25 
26 #ifndef LELY_NO_CO_MASTER
27 
28 #include "nmt_cfg.h"
29 #include <lely/co/dcf.h>
30 #include <lely/co/dev.h>
31 #include <lely/co/obj.h>
32 #include <lely/co/val.h>
33 #include <lely/util/diag.h>
34 
35 #include <assert.h>
36 #include <inttypes.h>
37 #include <stdlib.h>
38 
39 #ifndef LELY_CO_NMT_CFG_RESET_TIMEOUT
40 
44 #define LELY_CO_NMT_CFG_RESET_TIMEOUT 1000
45 #endif
46 
47 struct __co_nmt_cfg_state;
50 
52 struct __co_nmt_cfg {
66  co_unsigned8_t id;
68  co_unsigned32_t assignment;
72  co_unsigned32_t ac;
74  struct co_sdo_req req;
78  co_unsigned32_t n_1f22;
79 };
80 
86 static int co_nmt_cfg_recv(const struct can_msg *msg, void *data);
87 
93 static int co_nmt_cfg_timer(const struct timespec *tp, void *data);
94 
101 static void co_nmt_cfg_dn_con(co_csdo_t *sdo, co_unsigned16_t idx,
102  co_unsigned8_t subidx, co_unsigned32_t ac, void *data);
103 
108 static void co_nmt_cfg_enter(co_nmt_cfg_t *cfg, co_nmt_cfg_state_t *next);
109 
117 static inline void co_nmt_cfg_emit_recv(
118  co_nmt_cfg_t *cfg, const struct can_msg *msg);
119 
127 static inline void co_nmt_cfg_emit_time(
128  co_nmt_cfg_t *cfg, const struct timespec *tp);
129 
139 static inline void co_nmt_cfg_emit_dn_con(co_nmt_cfg_t *cfg,
140  co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac);
141 
149 static inline void co_nmt_cfg_emit_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac);
150 
154  co_nmt_cfg_state_t *(*on_enter)(co_nmt_cfg_t *cfg);
164  co_nmt_cfg_state_t *(*on_recv)(
165  co_nmt_cfg_t *cfg, const struct can_msg *msg);
174  co_nmt_cfg_state_t *(*on_time)(
175  co_nmt_cfg_t *cfg, const struct timespec *tp);
185  co_nmt_cfg_state_t *(*on_res)(co_nmt_cfg_t *cfg, co_unsigned32_t ac);
197  co_nmt_cfg_state_t *(*on_dn_con)(co_nmt_cfg_t *cfg, co_unsigned16_t idx,
198  co_unsigned8_t subidx, co_unsigned32_t ac);
200  void (*on_leave)(co_nmt_cfg_t *cfg);
201 };
202 
203 #define LELY_CO_DEFINE_STATE(name, ...) \
204  static co_nmt_cfg_state_t *const name = \
205  &(co_nmt_cfg_state_t){ __VA_ARGS__ };
206 
209 
210 // clang-format off
211 LELY_CO_DEFINE_STATE(co_nmt_cfg_abort_state,
212  .on_enter = &co_nmt_cfg_abort_on_enter
213 )
214 // clang-format on
215 
218 
224  co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac);
225 
226 // clang-format off
227 LELY_CO_DEFINE_STATE(co_nmt_cfg_restore_state,
228  .on_enter = &co_nmt_cfg_restore_on_enter,
229  .on_dn_con = &co_nmt_cfg_restore_on_dn_con
230 )
231 // clang-format on
232 
235 
238  co_nmt_cfg_t *cfg, const struct can_msg *msg);
239 
242  co_nmt_cfg_t *cfg, const struct timespec *tp);
243 
244 // clang-format off
245 LELY_CO_DEFINE_STATE(co_nmt_cfg_reset_state,
246  .on_enter = &co_nmt_cfg_reset_on_enter,
247  .on_recv = &co_nmt_cfg_reset_on_recv,
248  .on_time = &co_nmt_cfg_reset_on_time
249 )
250 // clang-format on
251 
254 
260  co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac);
261 
264 
265 // clang-format off
266 LELY_CO_DEFINE_STATE(co_nmt_cfg_store_1f20_state,
267  .on_enter = &co_nmt_cfg_store_1f20_on_enter,
268  .on_dn_con = &co_nmt_cfg_store_1f20_on_dn_con,
269  .on_leave = &co_nmt_cfg_store_1f20_on_leave
270 )
271 // clang-format on
272 
275 
281  co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac);
282 
283 // clang-format off
284 LELY_CO_DEFINE_STATE(co_nmt_cfg_store_1f22_state,
285  .on_enter = &co_nmt_cfg_store_1f22_on_enter,
286  .on_dn_con = &co_nmt_cfg_store_1f22_on_dn_con
287 )
288 // clang-format on
289 
292 
295  co_nmt_cfg_t *cfg, co_unsigned32_t ac);
296 
297 // clang-format off
298 LELY_CO_DEFINE_STATE(co_nmt_cfg_user_state,
299  .on_enter = &co_nmt_cfg_user_on_enter,
300  .on_res = &co_nmt_cfg_user_on_res
301 )
302 // clang-format on
303 
304 #undef LELY_CO_DEFINE_STATE
305 
306 void *
307 __co_nmt_cfg_alloc(void)
308 {
309  void *ptr = malloc(sizeof(struct __co_nmt_cfg));
310  if (!ptr)
311  set_errc(errno2c(errno));
312  return ptr;
313 }
314 
315 void
316 __co_nmt_cfg_free(void *ptr)
317 {
318  free(ptr);
319 }
320 
321 struct __co_nmt_cfg *
322 __co_nmt_cfg_init(struct __co_nmt_cfg *cfg, can_net_t *net, co_dev_t *dev,
323  co_nmt_t *nmt)
324 {
325  assert(cfg);
326  assert(net);
327  assert(dev);
328  assert(nmt);
329 
330  int errc = 0;
331 
332  cfg->net = net;
333  cfg->dev = dev;
334  cfg->nmt = nmt;
335 
336  cfg->state = NULL;
337 
338  cfg->recv = can_recv_create();
339  if (!cfg->recv) {
340  errc = get_errc();
341  goto error_create_recv;
342  }
344 
345  cfg->timer = can_timer_create();
346  if (!cfg->timer) {
347  errc = get_errc();
348  goto error_create_timer;
349  }
351 
352  cfg->id = 0;
353  cfg->assignment = 0;
354 
355  cfg->sdo = NULL;
356 
357  cfg->ac = 0;
358 
359  co_sdo_req_init(&cfg->req);
360  cfg->dev_1f20 = NULL;
361  cfg->n_1f22 = 0;
362 
363  return cfg;
364 
365  // can_timer_destroy(cfg->timer);
366 error_create_timer:
367  can_recv_destroy(cfg->recv);
368 error_create_recv:
369  set_errc(errc);
370  return NULL;
371 }
372 
373 void
374 __co_nmt_cfg_fini(struct __co_nmt_cfg *cfg)
375 {
376  assert(cfg);
377 
378  assert(!cfg->dev_1f20);
379  co_sdo_req_fini(&cfg->req);
380 
381  co_csdo_destroy(cfg->sdo);
382 
383  can_timer_destroy(cfg->timer);
384  can_recv_destroy(cfg->recv);
385 }
386 
387 co_nmt_cfg_t *
389 {
390  int errc = 0;
391 
392  co_nmt_cfg_t *cfg = __co_nmt_cfg_alloc();
393  if (!cfg) {
394  errc = get_errc();
395  goto error_alloc_cfg;
396  }
397 
398  if (!__co_nmt_cfg_init(cfg, net, dev, nmt)) {
399  errc = get_errc();
400  goto error_init_cfg;
401  }
402 
403  return cfg;
404 
405 error_init_cfg:
406  __co_nmt_cfg_free(cfg);
407 error_alloc_cfg:
408  set_errc(errc);
409  return NULL;
410 }
411 
412 void
414 {
415  if (cfg) {
416  __co_nmt_cfg_fini(cfg);
417  __co_nmt_cfg_free(cfg);
418  }
419 }
420 
421 int
422 co_nmt_cfg_cfg_req(co_nmt_cfg_t *cfg, co_unsigned8_t id, int timeout,
423  co_csdo_ind_t *dn_ind, co_csdo_ind_t *up_ind, void *data)
424 {
425  assert(cfg);
426 
427  if (!id || id > CO_NUM_NODES) {
429  return -1;
430  }
431 
432  if (cfg->state) {
434  return -1;
435  }
436 
437  cfg->id = id;
438 
439  co_csdo_destroy(cfg->sdo);
440  cfg->sdo = co_csdo_create(cfg->net, NULL, cfg->id);
441  if (!cfg->sdo)
442  return -1;
443  co_csdo_set_timeout(cfg->sdo, timeout);
444  co_csdo_set_dn_ind(cfg->sdo, dn_ind, data);
445  co_csdo_set_up_ind(cfg->sdo, up_ind, data);
446 
447  co_nmt_cfg_enter(cfg, co_nmt_cfg_restore_state);
448 
449  return 0;
450 }
451 
452 int
453 co_nmt_cfg_cfg_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
454 {
455  assert(cfg);
456 
457  co_nmt_cfg_emit_res(cfg, ac);
458 
459  return 0;
460 }
461 
462 static int
463 co_nmt_cfg_recv(const struct can_msg *msg, void *data)
464 {
465  assert(msg);
466  co_nmt_cfg_t *cfg = data;
467  assert(cfg);
468 
469  co_nmt_cfg_emit_recv(cfg, msg);
470 
471  return 0;
472 }
473 
474 static int
475 co_nmt_cfg_timer(const struct timespec *tp, void *data)
476 {
477  assert(tp);
478  co_nmt_cfg_t *cfg = data;
479  assert(cfg);
480 
481  co_nmt_cfg_emit_time(cfg, tp);
482 
483  return 0;
484 }
485 
486 static void
487 co_nmt_cfg_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
488  co_unsigned32_t ac, void *data)
489 {
490  (void)sdo;
491  co_nmt_cfg_t *cfg = data;
492  assert(cfg);
493 
494  co_nmt_cfg_emit_dn_con(cfg, idx, subidx, ac);
495 }
496 
497 static void
499 {
500  assert(cfg);
501 
502  while (next) {
503  co_nmt_cfg_state_t *prev = cfg->state;
504  cfg->state = next;
505 
506  if (prev && prev->on_leave)
507  prev->on_leave(cfg);
508 
509  next = next->on_enter ? next->on_enter(cfg) : NULL;
510  }
511 }
512 
513 static inline void
514 co_nmt_cfg_emit_recv(co_nmt_cfg_t *cfg, const struct can_msg *msg)
515 {
516  assert(cfg);
517  assert(cfg->state);
518  assert(cfg->state->on_recv);
519 
520  co_nmt_cfg_enter(cfg, cfg->state->on_recv(cfg, msg));
521 }
522 
523 static inline void
524 co_nmt_cfg_emit_time(co_nmt_cfg_t *cfg, const struct timespec *tp)
525 {
526  assert(cfg);
527  assert(cfg->state);
528  assert(cfg->state->on_time);
529 
530  co_nmt_cfg_enter(cfg, cfg->state->on_time(cfg, tp));
531 }
532 
533 static inline void
534 co_nmt_cfg_emit_dn_con(co_nmt_cfg_t *cfg, co_unsigned16_t idx,
535  co_unsigned8_t subidx, co_unsigned32_t ac)
536 {
537  assert(cfg);
538  assert(cfg->state);
539  assert(cfg->state->on_dn_con);
540 
541  co_nmt_cfg_enter(cfg, cfg->state->on_dn_con(cfg, idx, subidx, ac));
542 }
543 
544 static inline void
545 co_nmt_cfg_emit_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
546 {
547  assert(cfg);
548  assert(cfg->state);
549  assert(cfg->state->on_res);
550 
551  co_nmt_cfg_enter(cfg, cfg->state->on_res(cfg, ac));
552 }
553 
554 static co_nmt_cfg_state_t *
556 {
557  assert(cfg);
558 
559  can_recv_stop(cfg->recv);
560  can_timer_stop(cfg->timer);
561 
562  co_nmt_cfg_con(cfg->nmt, cfg->id, cfg->ac);
563 
564  return NULL;
565 }
566 
567 static co_nmt_cfg_state_t *
569 {
570  assert(cfg);
571 
572  cfg->ac = 0;
573 
574  // Retrieve the slave assignment for the node.
575  cfg->assignment = co_dev_get_val_u32(cfg->dev, 0x1f81, cfg->id);
576 
577  // Abort the configuration request if the slave is not in the network
578  // list.
579  if (!(cfg->assignment & 0x01))
580  return co_nmt_cfg_abort_state;
581 
582  // Check if the slave can be used without prior resetting (bit 7).
583  if (!(cfg->assignment & 0x80))
584  return co_nmt_cfg_store_1f20_state;
585 
586  // Retrieve the sub-index of object 1011 of the slave that is used to
587  // initiate the restore operation.
588  co_unsigned8_t subidx = co_dev_get_val_u8(cfg->dev, 0x1f8a, cfg->id);
589 
590  // If the sub-index is 0, no restore is sent to the slave.
591  if (!subidx)
592  return co_nmt_cfg_store_1f20_state;
593 
594  // Write the value 'load' to sub-index of object 1011 on the slave.
595  // clang-format off
596  if (co_csdo_dn_val_req(cfg->sdo, 0x1011, subidx, CO_DEFTYPE_UNSIGNED32,
597  &(co_unsigned32_t){ UINT32_C(0x64616f6c) },
598  &co_nmt_cfg_dn_con, cfg) == -1) {
599  // clang-format on
600  cfg->ac = CO_SDO_AC_ERROR;
601  return co_nmt_cfg_abort_state;
602  }
603 
604  return NULL;
605 }
606 
607 static co_nmt_cfg_state_t *
608 co_nmt_cfg_restore_on_dn_con(co_nmt_cfg_t *cfg, co_unsigned16_t idx,
609  co_unsigned8_t subidx, co_unsigned32_t ac)
610 {
611  assert(cfg);
612  (void)idx;
613 
614  if (ac) {
615  cfg->ac = ac;
616  return co_nmt_cfg_abort_state;
617  }
618 
619  switch (subidx) {
620  case 0x02:
621  // Issue the NMT reset communication command after restoring
622  // communication related parameters.
624  break;
625  default:
626  // Issue the NMT reset node command after restoring application
627  // or manufacturer-specific parameters.
629  break;
630  }
631 
632  return co_nmt_cfg_reset_state;
633 }
634 
635 static co_nmt_cfg_state_t *
637 {
638  assert(cfg);
639 
640  // Start the CAN frame receiver for the boot-up message.
641  can_recv_start(cfg->recv, cfg->net, CO_NMT_EC_CANID(cfg->id), 0);
642  // Wait until we receive a boot-up message.
644 
645  return NULL;
646 }
647 
648 static co_nmt_cfg_state_t *
650 {
651  (void)cfg;
652  (void)msg;
653 
654  can_recv_stop(cfg->recv);
655  return co_nmt_cfg_store_1f20_state;
656 }
657 
658 static co_nmt_cfg_state_t *
659 co_nmt_cfg_reset_on_time(co_nmt_cfg_t *cfg, const struct timespec *tp)
660 {
661  assert(cfg);
662  (void)tp;
663 
664  cfg->ac = CO_SDO_AC_TIMEOUT;
665  return co_nmt_cfg_abort_state;
666 }
667 
668 static co_nmt_cfg_state_t *
670 {
671 #if LELY_NO_CO_DCF
672  (void)cfg;
673 
674  return co_nmt_cfg_store_1f22_state;
675 #else // !LELY_NO_CO_DCF
676  assert(cfg);
677 
678  // Check if the DCF is available and the format is plain ASCII.
679  co_sub_t *sub = co_dev_find_sub(cfg->dev, 0x1f20, cfg->id);
680  if (!sub || co_dev_get_val_u8(cfg->dev, 0x1f21, cfg->id) != 0)
681  return co_nmt_cfg_store_1f22_state;
682 
683  // Upload the DCF.
684  struct co_sdo_req *req = &cfg->req;
685  co_sdo_req_clear(req);
686  cfg->ac = co_sub_up_ind(sub, req);
687  if (cfg->ac) {
688  diag(DIAG_ERROR, 0,
689  "SDO abort code %08" PRIX32
690  " on upload request of object 1F20:%02X (Store DCF): %s",
691  cfg->ac, cfg->id, co_sdo_ac2str(cfg->ac));
692  return co_nmt_cfg_abort_state;
693  }
694 
695  if (!co_sdo_req_first(req) || !co_sdo_req_last(req)) {
696  diag(DIAG_WARNING, 0,
697  "object 1F20:%02X (Store DCF) unusable for configuration request",
698  cfg->id);
699  return co_nmt_cfg_store_1f22_state;
700  }
701 
702  // Ignore an empty DCF.
703  if (!req->nbyte)
704  return co_nmt_cfg_store_1f22_state;
705 
706  // Parse the DCF.
707  assert(!cfg->dev_1f20);
709  req->buf, (const char *)req->buf + req->nbyte, NULL);
710  if (!cfg->dev_1f20) {
711  cfg->ac = CO_SDO_AC_ERROR;
712  return co_nmt_cfg_abort_state;
713  }
714 
715  return co_nmt_cfg_store_1f20_on_dn_con(cfg, 0, 0, 0);
716 #endif // !LELY_NO_CO_DCF
717 }
718 
719 static co_nmt_cfg_state_t *
721  co_unsigned8_t subidx, co_unsigned32_t ac)
722 {
723  assert(cfg);
724  assert(cfg->dev_1f20);
725 
726  if (ac) {
727  cfg->ac = ac;
728  return co_nmt_cfg_abort_state;
729  }
730 
731  // Find the next (or first) sub-object in the object dictionary.
732  co_obj_t *obj;
733  co_sub_t *sub;
734  if (idx) {
735  obj = co_dev_find_obj(cfg->dev_1f20, idx);
736  assert(obj);
737  sub = co_obj_find_sub(obj, subidx);
738  assert(sub);
739  sub = co_sub_next(sub);
740  } else {
741  obj = co_dev_first_obj(cfg->dev_1f20);
742  if (!obj)
743  return co_nmt_cfg_store_1f22_state;
744  sub = co_obj_first_sub(obj);
745  }
746 
747  // Find the next sub-object to be written.
748  co_unsigned16_t type;
749  const void *val;
750  for (;; sub = co_sub_next(sub)) {
751  while (!sub) {
752  obj = co_obj_next(obj);
753  if (!obj)
754  return co_nmt_cfg_store_1f22_state;
755  sub = co_obj_first_sub(obj);
756  }
757  // Skip read-only sub-objects.
758  if (!(co_sub_get_access(sub) & CO_ACCESS_WRITE))
759  continue;
760  // Skip file-based sub-objects.
762  continue;
763  // Skip sub-objects containing the default value.
764  type = co_sub_get_type(sub);
765  val = co_sub_get_val(sub);
766 #ifndef LELY_NO_CO_OBJ_DEFAULT
767  const void *def = co_sub_get_def(sub);
768  if (!co_val_cmp(type, def, val))
769  continue;
770 #endif
771  break;
772  }
773 
774  // Write the value to the slave.
775  idx = co_obj_get_idx(obj);
776  subidx = co_sub_get_subidx(sub);
777  // clang-format off
778  if (co_csdo_dn_val_req(cfg->sdo, idx, subidx, type, val,
779  &co_nmt_cfg_dn_con, cfg) == -1) {
780  // clang-format on
781  cfg->ac = CO_SDO_AC_ERROR;
782  return co_nmt_cfg_abort_state;
783  }
784 
785  return NULL;
786 }
787 
788 static void
790 {
791  assert(cfg);
792 
793  co_dev_destroy(cfg->dev_1f20);
794  cfg->dev_1f20 = NULL;
795 }
796 
797 static co_nmt_cfg_state_t *
799 {
800  assert(cfg);
801 
802  co_sub_t *sub = co_dev_find_sub(cfg->dev, 0x1f22, cfg->id);
803  if (!sub)
804  return co_nmt_cfg_user_state;
805 
806  // Upload the concise DCF.
807  struct co_sdo_req *req = &cfg->req;
808  co_sdo_req_clear(req);
809  cfg->ac = co_sub_up_ind(sub, req);
810  if (cfg->ac) {
811  diag(DIAG_ERROR, 0,
812  "SDO abort code %08" PRIX32
813  " on upload request of object 1F22:%02X (Concise DCF): %s",
814  cfg->ac, cfg->id, co_sdo_ac2str(cfg->ac));
815  return co_nmt_cfg_abort_state;
816  }
817 
818  if (!co_sdo_req_first(req) || !co_sdo_req_last(req)) {
819  diag(DIAG_WARNING, 0,
820  "object 1F22:%02X (Concise DCF) unusable for configuration request",
821  cfg->id);
822  return co_nmt_cfg_user_state;
823  }
824 
825  // Ignore an empty concise DCF.
826  if (!req->nbyte)
827  return co_nmt_cfg_user_state;
828 
829  const uint_least8_t *begin = req->buf;
830  const uint_least8_t *end = begin + req->nbyte;
831 
832  // Read the total number of entries.
833  if (co_val_read(CO_DEFTYPE_UNSIGNED32, &cfg->n_1f22, begin, end) != 4) {
834  cfg->ac = CO_SDO_AC_TYPE_LEN_LO;
835  return co_nmt_cfg_abort_state;
836  }
837  begin += 4;
838 
839  req->nbyte = end - begin;
840  req->offset = begin - (const uint_least8_t *)req->buf;
841 
842  return co_nmt_cfg_store_1f22_on_dn_con(cfg, 0, 0, 0);
843 }
844 
845 static co_nmt_cfg_state_t *
847  co_unsigned8_t subidx, co_unsigned32_t ac)
848 {
849  assert(cfg);
850  struct co_sdo_req *req = &cfg->req;
851 
852  if (ac) {
853  cfg->ac = ac;
854  return co_nmt_cfg_abort_state;
855  }
856 
857  if (!cfg->n_1f22--)
858  return co_nmt_cfg_user_state;
859 
860  const uint_least8_t *begin =
861  (const uint_least8_t *)req->buf + req->offset;
862  const uint_least8_t *end = begin + req->nbyte;
863 
864  // Read the object index.
865  if (co_val_read(CO_DEFTYPE_UNSIGNED16, &idx, begin, end) != 2) {
866  cfg->ac = CO_SDO_AC_TYPE_LEN_LO;
867  return co_nmt_cfg_abort_state;
868  }
869  begin += 2;
870  // Read the object sub-index.
871  if (co_val_read(CO_DEFTYPE_UNSIGNED8, &subidx, begin, end) != 1) {
872  cfg->ac = CO_SDO_AC_TYPE_LEN_LO;
873  return co_nmt_cfg_abort_state;
874  }
875  begin += 1;
876  // Read the value size (in bytes).
877  co_unsigned32_t size;
878  if (co_val_read(CO_DEFTYPE_UNSIGNED32, &size, begin, end) != 4) {
879  cfg->ac = CO_SDO_AC_TYPE_LEN_LO;
880  return co_nmt_cfg_abort_state;
881  }
882  begin += 4;
883 
884  if (end - begin < (ptrdiff_t)size) {
885  cfg->ac = CO_SDO_AC_TYPE_LEN_LO;
886  return co_nmt_cfg_abort_state;
887  }
888 
889  req->nbyte = end - begin - size;
890  req->offset = begin + size - (const uint_least8_t *)req->buf;
891 
892  // Write the value to the slave.
893  // clang-format off
894  if (co_csdo_dn_req(cfg->sdo, idx, subidx, begin, size,
895  &co_nmt_cfg_dn_con, cfg) == -1) {
896  // clang-format on
897  cfg->ac = CO_SDO_AC_ERROR;
898  return co_nmt_cfg_abort_state;
899  }
900 
901  return NULL;
902 }
903 
904 static co_nmt_cfg_state_t *
906 {
907  assert(cfg);
908 
909  co_nmt_cfg_ind(cfg->nmt, cfg->id, cfg->sdo);
910 
911  return NULL;
912 }
913 
914 static co_nmt_cfg_state_t *
915 co_nmt_cfg_user_on_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
916 {
917  assert(cfg);
918 
919  cfg->ac = ac;
920  return co_nmt_cfg_abort_state;
921 }
922 
923 #endif // !LELY_NO_CO_MASTER
co_nmt_cfg_state_t *(* on_time)(co_nmt_cfg_t *cfg, const struct timespec *tp)
A pointer to the transition function invoked when a timeout occurs.
Definition: nmt_cfg.c:174
int co_nmt_cs_req(co_nmt_t *nmt, co_unsigned8_t cs, co_unsigned8_t id)
Submits an NMT request to a slave.
Definition: nmt.c:1569
A CANopen SDO upload/download request.
Definition: sdo.h:178
A CAN or CAN FD format frame.
Definition: msg.h:87
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition: dev.h:56
static co_nmt_cfg_state_t * co_nmt_cfg_user_on_enter(co_nmt_cfg_t *cfg)
The entry function of the &#39;user-defined configuration&#39; state.
Definition: nmt_cfg.c:905
void co_csdo_set_timeout(co_csdo_t *sdo, int timeout)
Sets the timeout of a Client-SDO.
Definition: csdo.c:945
static void co_nmt_cfg_emit_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
Invokes the &#39;result received&#39; transition function of the current state of a &#39;configuration request&#39;...
Definition: nmt_cfg.c:545
A CAN network interface.
Definition: net.c:37
void co_nmt_cfg_destroy(co_nmt_cfg_t *cfg)
Destroys a CANopen NMT &#39;configuration request&#39;.
Definition: nmt_cfg.c:413
size_t size
The total size (in bytes) of the value to be uploaded/downloaded.
Definition: sdo.h:184
A CANopen sub-object.
Definition: obj.h:54
#define CO_ACCESS_WRITE
The object can be written.
Definition: obj.h:60
static void co_nmt_cfg_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 &#39;configuration request&#39;.
Definition: nmt_cfg.c:487
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
co_obj_t * co_obj_next(const co_obj_t *obj)
Finds the next object in the object dictionary of a CANopen device.
Definition: obj.c:137
static int co_nmt_cfg_recv(const struct can_msg *msg, void *data)
The CAN receive callback function for a &#39;configuration request&#39;.
Definition: nmt_cfg.c:463
can_timer_t * timer
A pointer to the CAN timer.
Definition: nmt_cfg.c:64
static co_nmt_cfg_state_t * co_nmt_cfg_reset_on_recv(co_nmt_cfg_t *cfg, const struct can_msg *msg)
The &#39;CAN frame received&#39; transition function of the &#39;reset&#39; state.
Definition: nmt_cfg.c:649
void co_sdo_req_clear(struct co_sdo_req *req)
Clears a CANopen SDO upload/download request, including its buffer.
Definition: sdo.c:129
#define CO_OBJ_FLAGS_DOWNLOAD_FILE
If a write access is performed for the object, the data is stored in a file.
Definition: obj.h:102
co_sub_t * co_obj_first_sub(const co_obj_t *obj)
Finds the first sub-object (with the lowest sub-index) in a CANopen object.
Definition: obj.c:234
co_obj_t * co_dev_first_obj(const co_dev_t *dev)
Finds the first object (with the lowest index) in the object dictionary of a CANopen device...
Definition: dev.c:306
co_unsigned32_t n_1f22
The number of entries in the concise DCF in object 1F22.
Definition: nmt_cfg.c:78
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
void(* on_leave)(co_nmt_cfg_t *cfg)
A pointer to the function invoked when the current state is left.
Definition: nmt_cfg.c:200
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
co_dev_t * dev_1f20
The object dictionary stored in object 1F20 (Store DCF).
Definition: nmt_cfg.c:76
const void * co_sub_get_def(const co_sub_t *sub)
Returns a pointer to the default value of a CANopen sub-object.
Definition: obj.c:650
void co_nmt_cfg_ind(co_nmt_t *nmt, co_unsigned8_t id, co_csdo_t *sdo)
The CANopen NMT &#39;update configuration&#39; indication function, invoked when a configuration request is r...
Definition: nmt.c:2049
static co_nmt_cfg_state_t * co_nmt_cfg_restore_on_dn_con(co_nmt_cfg_t *cfg, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac)
The &#39;SDO download confirmation&#39; transition function of the &#39;restore configuration&#39; state...
Definition: nmt_cfg.c:608
#define CO_SDO_AC_ERROR
SDO abort code: General error.
Definition: sdo.h:150
#define LELY_CO_NMT_CFG_RESET_TIMEOUT
The timeout (in milliseconds) after sending the NMT &#39;reset communication&#39; or &#39;reset node&#39; command...
Definition: nmt_cfg.c:44
static co_nmt_cfg_state_t * co_nmt_cfg_reset_on_time(co_nmt_cfg_t *cfg, const struct timespec *tp)
The &#39;timeout&#39; transition function of the &#39;reset&#39; state.
Definition: nmt_cfg.c:659
static co_nmt_cfg_state_t * co_nmt_cfg_store_1f20_on_enter(co_nmt_cfg_t *cfg)
The entry function of the &#39;store object 1F20&#39; state.
Definition: nmt_cfg.c:669
static void co_nmt_cfg_store_1f20_on_leave(co_nmt_cfg_t *cfg)
The exit function of the &#39;store object 1F20&#39; state.
Definition: nmt_cfg.c:789
int co_csdo_dn_val_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned16_t type, const void *val, co_csdo_dn_con_t *con, void *data)
Submits a download request to a remote Server-SDO.
Definition: csdo.c:1034
This header file is part of the CANopen library; it contains the CANopen value declarations.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
unsigned int co_sub_get_access(const co_sub_t *sub)
Returns the access type of a CANopen sub-object.
Definition: obj.c:745
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
co_unsigned32_t ac
The SDO abort code.
Definition: nmt_cfg.c:72
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition: net.c:537
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50
static co_nmt_cfg_state_t * co_nmt_cfg_user_on_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
The &#39;result received&#39; function of the &#39;user-defined configuration&#39; state.
Definition: nmt_cfg.c:915
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
static int co_nmt_cfg_timer(const struct timespec *tp, void *data)
The CAN timer callback function for a &#39;configuration request&#39;.
Definition: nmt_cfg.c:475
void can_timer_stop(can_timer_t *timer)
Stops a CAN timer and unregisters it with a network interface.
Definition: net.c:468
struct co_sdo_req req
The CANopen SDO upload request used for reading sub-objects.
Definition: nmt_cfg.c:74
size_t co_val_read(co_unsigned16_t type, void *val, const uint_least8_t *begin, const uint_least8_t *end)
Reads a value of the specified data type from a memory buffer.
Definition: val.c:481
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition: type.h:47
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition: net.c:562
co_nmt_cfg_state_t *(* on_enter)(co_nmt_cfg_t *cfg)
A pointer to the function invoked when a new state is entered.
Definition: nmt_cfg.c:154
#define CO_SDO_AC_TIMEOUT
SDO abort code: SDO protocol timed out.
Definition: sdo.h:66
const void * co_sub_get_val(const co_sub_t *sub)
Returns a pointer to the current value of a CANopen sub-object.
Definition: obj.c:679
This is the internal header file of the CANopen library.
static void co_nmt_cfg_emit_recv(co_nmt_cfg_t *cfg, const struct can_msg *msg)
Invokes the &#39;CAN frame received&#39; transition function of the current state of a &#39;configuration request...
Definition: nmt_cfg.c:514
#define CO_NMT_CS_RESET_NODE
The NMT command specifier &#39;reset node&#39;.
Definition: nmt.h:49
Operation in progress.
Definition: errnum.h:125
co_unsigned32_t co_sub_up_ind(const co_sub_t *sub, struct co_sdo_req *req)
Invokes the upload indication function of a CANopen sub-object, registered with co_sub_set_up_ind().
Definition: obj.c:1019
static void co_nmt_cfg_emit_time(co_nmt_cfg_t *cfg, const struct timespec *tp)
Invokes the &#39;timeout&#39; transition function of the current state of a &#39;configuration request&#39;...
Definition: nmt_cfg.c:524
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function...
Definition: errnum.c:947
A CAN timer.
Definition: net.c:63
static void co_nmt_cfg_emit_dn_con(co_nmt_cfg_t *cfg, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac)
Invokes the &#39;SDO download confirmation&#39; transition function of the current state of a &#39;configuration ...
Definition: nmt_cfg.c:534
A CANopen Client-SDO.
Definition: csdo.c:45
#define CO_NMT_EC_CANID(id)
The CAN identifier used for both node guarding and heartbeat monitoring.
Definition: nmt.h:76
void can_timer_destroy(can_timer_t *timer)
Destroys a CAN timer.
Definition: net.c:407
void co_csdo_set_dn_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO download requ...
Definition: csdo.c:967
A CANopen NMT master/slave service.
Definition: nmt.c:104
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition: type.h:44
co_nmt_cfg_t * co_nmt_cfg_create(can_net_t *net, co_dev_t *dev, co_nmt_t *nmt)
Creates a new CANopen NMT &#39;configuration request&#39;.
Definition: nmt_cfg.c:388
co_sub_t * co_sub_next(const co_sub_t *sub)
Finds the next sub-object in a CANopen object.
Definition: obj.c:511
static co_nmt_cfg_state_t * co_nmt_cfg_store_1f22_on_dn_con(co_nmt_cfg_t *cfg, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac)
The &#39;SDO download confirmation&#39; transition function of the &#39;store object 1F22&#39; state.
Definition: nmt_cfg.c:846
size_t offset
The offset of the bytes at buf.
Definition: sdo.h:193
An error.
Definition: diag.h:49
Invalid argument.
Definition: errnum.h:129
unsigned int co_sub_get_flags(const co_sub_t *sub)
Returns the object flags of a CANopen sub-object.
Definition: obj.c:785
co_dev_t * dev
A pointer to a CANopen device.
Definition: nmt_cfg.c:56
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
This header file is part of the utilities library; it contains the diagnostic declarations.
A CANopen NMT &#39;configuration request&#39; service.
Definition: nmt_cfg.c:52
void co_csdo_ind_t(const co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
The type of a CANopen Client-SDO request progress indication function, used to notify the user of the...
Definition: csdo.h:79
co_unsigned32_t assignment
The NMT slave assignment (object 1F81).
Definition: nmt_cfg.c:68
int co_val_cmp(co_unsigned16_t type, const void *v1, const void *v2)
Compares two values of the specified data type.
Definition: val.c:397
A CANopen device.
Definition: dev.c:41
co_csdo_t * co_csdo_create(can_net_t *net, co_dev_t *dev, co_unsigned8_t num)
Creates a new CANopen Client-SDO service.
Definition: csdo.c:868
const char * co_sdo_ac2str(co_unsigned32_t ac)
Returns a string describing an SDO abort code.
Definition: sdo.c:57
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
This is the internal header file of the NMT &#39;configuration request&#39; declarations. ...
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition: net.c:382
void co_csdo_destroy(co_csdo_t *sdo)
Destroys a CANopen Client-SDO service.
Definition: csdo.c:895
co_nmt_cfg_state_t * state
A pointer to the current state.
Definition: nmt_cfg.c:60
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: nmt_cfg.c:62
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
static co_nmt_cfg_state_t * co_nmt_cfg_store_1f22_on_enter(co_nmt_cfg_t *cfg)
The entry function of the &#39;store object 1F22&#39; state.
Definition: nmt_cfg.c:798
A warning.
Definition: diag.h:47
co_sub_t * co_dev_find_sub(const co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx)
Finds a sub-object in the object dictionary of a CANopen device.
Definition: dev.c:299
A CANopen NMT &#39;configuration request&#39; state.
Definition: nmt_cfg.c:152
void co_sdo_req_init(struct co_sdo_req *req)
Initializes a CANopen SDO upload/download request.
Definition: sdo.c:109
size_t nbyte
The number of bytes available at buf.
Definition: sdo.h:188
int co_csdo_dn_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
Submits a download request to a remote Server-SDO.
Definition: csdo.c:1012
co_nmt_t * nmt
A pointer to an NMT master service.
Definition: nmt_cfg.c:58
This header file is part of the CANopen library; it contains the device description declarations...
can_net_t * net
A pointer to a CAN network interface.
Definition: nmt_cfg.c:54
const void * buf
A pointer to the next bytes to be uploaded/downloaded.
Definition: sdo.h:186
co_nmt_cfg_state_t *(* on_res)(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
A pointer to the transition function invoked when an NMT&#39;update configuration&#39; step completes...
Definition: nmt_cfg.c:185
co_csdo_t * sdo
A pointer to the Client-SDO used to access slave objects.
Definition: nmt_cfg.c:70
static co_nmt_cfg_state_t * co_nmt_cfg_restore_on_enter(co_nmt_cfg_t *cfg)
The entry function of the &#39;restore configuration&#39; state.
Definition: nmt_cfg.c:568
void co_nmt_cfg_con(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned32_t ac)
The CANopen NMT &#39;configuration request&#39; confirmation function, invoked when a configuration request c...
Definition: nmt.c:2063
co_nmt_cfg_state_t *(* on_dn_con)(co_nmt_cfg_t *cfg, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac)
A pointer to the transition function invoked when an SDO download request completes.
Definition: nmt_cfg.c:197
co_unsigned8_t co_sub_get_subidx(const co_sub_t *sub)
Returns the sub-index of a CANopen sub-object.
Definition: obj.c:528
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
void co_dev_destroy(co_dev_t *dev)
Destroys a CANopen device, including all objects in its object dictionary.
Definition: dev.c:175
A CAN frame receiver.
Definition: net.c:99
void co_sdo_req_fini(struct co_sdo_req *req)
Finalizes a CANopen SDO upload/download request.
Definition: sdo.c:121
co_unsigned16_t co_sub_get_type(const co_sub_t *sub)
Returns the data type of a CANopen sub-object.
Definition: obj.c:570
co_sub_t * co_obj_find_sub(const co_obj_t *obj, co_unsigned8_t subidx)
Finds a sub-object in a CANopen object.
Definition: obj.c:225
static void co_nmt_cfg_enter(co_nmt_cfg_t *cfg, co_nmt_cfg_state_t *next)
Enters the specified state of a &#39;configuration request; and invokes the exit and entry functions...
Definition: nmt_cfg.c:498
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition: obj.c:154
int co_nmt_cfg_cfg_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
Indicates the result of the &#39;update configuration&#39; step of an NMT &#39;configuration request&#39;.
Definition: nmt_cfg.c:453
co_unsigned8_t id
The node-ID.
Definition: nmt_cfg.c:66
#define CO_NMT_CS_RESET_COMM
The NMT command specifier &#39;reset communication&#39;.
Definition: nmt.h:52
static co_nmt_cfg_state_t * co_nmt_cfg_abort_on_enter(co_nmt_cfg_t *cfg)
The entry function of the &#39;abort&#39; state.
Definition: nmt_cfg.c:555
void co_csdo_set_up_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO upload reques...
Definition: csdo.c:987
int co_nmt_cfg_cfg_req(co_nmt_cfg_t *cfg, co_unsigned8_t id, int timeout, co_csdo_ind_t *dn_ind, co_csdo_ind_t *up_ind, void *data)
Starts a CANopen NMT &#39;configuration request&#39;.
Definition: nmt_cfg.c:422
A CANopen object.
Definition: obj.h:32
This header file is part of the CANopen library; it contains the object dictionary declarations...
static co_nmt_cfg_state_t * co_nmt_cfg_reset_on_enter(co_nmt_cfg_t *cfg)
The entry function of the &#39;reset&#39; state.
Definition: nmt_cfg.c:636
#define CO_SDO_AC_TYPE_LEN_LO
SDO abort code: Data type does not match, length of service parameter too low.
Definition: sdo.h:129
co_obj_t * co_dev_find_obj(const co_dev_t *dev, co_unsigned16_t idx)
Finds an object in the object dictionary of a CANopen device.
Definition: dev.c:288
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
This header file is part of the CANopen library; it contains the Electronic Data Sheet (EDS) and Devi...
co_nmt_cfg_state_t *(* on_recv)(co_nmt_cfg_t *cfg, const struct can_msg *msg)
A pointer to the transition function invoked when a CAN frame has been received.
Definition: nmt_cfg.c:164
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
co_dev_t * co_dev_create_from_dcf_text(const char *begin, const char *end, struct floc *at)
Creates a CANopen device from an EDS or DCF text string.
Definition: dcf.c:153
static co_nmt_cfg_state_t * co_nmt_cfg_store_1f20_on_dn_con(co_nmt_cfg_t *cfg, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac)
The &#39;SDO download confirmation&#39; transition function of the &#39;store object 1F20&#39; state.
Definition: nmt_cfg.c:720