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
44 #define LELY_CO_NMT_CFG_RESET_TIMEOUT 1000
45 #endif
46 
47 struct __co_nmt_cfg_state;
49 typedef const struct __co_nmt_cfg_state co_nmt_cfg_state_t;
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
This header file is part of the CANopen library; it contains the device description declarations.
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
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition: dev.h:56
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
void co_dev_destroy(co_dev_t *dev)
Destroys a CANopen device, including all objects in its object dictionary.
Definition: dev.c:175
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
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
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
void co_csdo_set_timeout(co_csdo_t *sdo, int timeout)
Sets the timeout of a Client-SDO.
Definition: csdo.c:945
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
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:967
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
void co_csdo_destroy(co_csdo_t *sdo)
Destroys a CANopen Client-SDO service.
Definition: csdo.c:895
This header file is part of the CANopen library; it contains the Electronic Data Sheet (EDS) and Devi...
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
This header file is part of the utilities library; it contains the diagnostic declarations.
@ DIAG_WARNING
A warning.
Definition: diag.h:47
@ 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
This header file is part of the CANopen library; it contains the object dictionary declarations.
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
const void * co_sub_get_val(const co_sub_t *sub)
Returns a pointer to the current value of a CANopen sub-object.
Definition: obj.c:679
co_sub_t * co_sub_next(const co_sub_t *sub)
Finds the next sub-object in a CANopen object.
Definition: obj.c:511
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition: obj.c:154
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
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
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_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
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
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
#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
#define CO_ACCESS_WRITE
The object can be written.
Definition: obj.h:60
unsigned int co_sub_get_access(const co_sub_t *sub)
Returns the access type of a CANopen sub-object.
Definition: obj.c:745
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
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
#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
void co_sdo_req_fini(struct co_sdo_req *req)
Finalizes a CANopen SDO upload/download request.
Definition: sdo.c:121
#define CO_SDO_AC_ERROR
SDO abort code: General error.
Definition: sdo.h:150
void co_sdo_req_clear(struct co_sdo_req *req)
Clears a CANopen SDO upload/download request, including its buffer.
Definition: sdo.c:129
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
const char * co_sdo_ac2str(co_unsigned32_t ac)
Returns a string describing an SDO abort code.
Definition: sdo.c:57
void co_sdo_req_init(struct co_sdo_req *req)
Initializes a CANopen SDO upload/download request.
Definition: sdo.c:109
#define CO_SDO_AC_TIMEOUT
SDO abort code: SDO protocol timed out.
Definition: sdo.h:66
void can_timer_stop(can_timer_t *timer)
Stops a CAN timer and unregisters it with a network interface.
Definition: net.c:468
void can_timer_set_func(can_timer_t *timer, can_timer_func_t *func, void *data)
Sets the callback function invoked when a CAN timer is triggered.
Definition: net.c:428
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition: net.c:537
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
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition: net.c:382
void can_timer_timeout(can_timer_t *timer, can_net_t *net, int timeout)
Starts a CAN timer and registers it with a network interface.
Definition: net.c:484
void can_recv_start(can_recv_t *recv, can_net_t *net, uint_least32_t id, uint_least8_t flags)
Registers a CAN frame receiver with a network interface and starts processing frames.
Definition: net.c:591
void can_timer_destroy(can_timer_t *timer)
Destroys a CAN timer.
Definition: net.c:407
void co_nmt_cfg_ind(co_nmt_t *nmt, co_unsigned8_t id, co_csdo_t *sdo)
The CANopen NMT 'update configuration' indication function, invoked when a configuration request is r...
Definition: nmt.c:2049
void co_nmt_cfg_con(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned32_t ac)
The CANopen NMT 'configuration request' confirmation function, invoked when a configuration request c...
Definition: nmt.c:2063
#define CO_NMT_EC_CANID(id)
The CAN identifier used for both node guarding and heartbeat monitoring.
Definition: nmt.h:76
#define CO_NMT_CS_RESET_NODE
The NMT command specifier 'reset node'.
Definition: nmt.h:49
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
#define CO_NMT_CS_RESET_COMM
The NMT command specifier 'reset communication'.
Definition: nmt.h:52
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 'SDO download confirmation' transition function of the 'store object 1F20' state.
Definition: nmt_cfg.c:720
static co_nmt_cfg_state_t * co_nmt_cfg_store_1f22_on_enter(co_nmt_cfg_t *cfg)
The entry function of the 'store object 1F22' state.
Definition: nmt_cfg.c:798
static void co_nmt_cfg_enter(co_nmt_cfg_t *cfg, co_nmt_cfg_state_t *next)
Enters the specified state of a 'configuration request; and invokes the exit and entry functions.
Definition: nmt_cfg.c:498
static co_nmt_cfg_state_t * co_nmt_cfg_abort_on_enter(co_nmt_cfg_t *cfg)
The entry function of the 'abort' state.
Definition: nmt_cfg.c:555
static co_nmt_cfg_state_t * co_nmt_cfg_reset_on_recv(co_nmt_cfg_t *cfg, const struct can_msg *msg)
The 'CAN frame received' transition function of the 'reset' state.
Definition: nmt_cfg.c:649
void co_nmt_cfg_destroy(co_nmt_cfg_t *cfg)
Destroys a CANopen NMT 'configuration request'.
Definition: nmt_cfg.c:413
static co_nmt_cfg_state_t * co_nmt_cfg_user_on_enter(co_nmt_cfg_t *cfg)
The entry function of the 'user-defined configuration' state.
Definition: nmt_cfg.c:905
static co_nmt_cfg_state_t * co_nmt_cfg_reset_on_enter(co_nmt_cfg_t *cfg)
The entry function of the 'reset' state.
Definition: nmt_cfg.c:636
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 'configuration request'.
Definition: nmt_cfg.c:422
static co_nmt_cfg_state_t * co_nmt_cfg_store_1f20_on_enter(co_nmt_cfg_t *cfg)
The entry function of the 'store object 1F20' state.
Definition: nmt_cfg.c:669
static int co_nmt_cfg_recv(const struct can_msg *msg, void *data)
The CAN receive callback function for a 'configuration request'.
Definition: nmt_cfg.c:463
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 'configuration request'.
Definition: nmt_cfg.c:388
static co_nmt_cfg_state_t * co_nmt_cfg_user_on_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
The 'result received' function of the 'user-defined configuration' state.
Definition: nmt_cfg.c:915
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 'SDO download confirmation' transition function of the 'restore configuration' state.
Definition: nmt_cfg.c:608
static co_nmt_cfg_state_t * co_nmt_cfg_reset_on_time(co_nmt_cfg_t *cfg, const struct timespec *tp)
The 'timeout' transition function of the 'reset' state.
Definition: nmt_cfg.c:659
static void co_nmt_cfg_emit_recv(co_nmt_cfg_t *cfg, const struct can_msg *msg)
Invokes the 'CAN frame received' transition function of the current state of a 'configuration request...
Definition: nmt_cfg.c:514
int co_nmt_cfg_cfg_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
Indicates the result of the 'update configuration' step of an NMT 'configuration request'.
Definition: nmt_cfg.c:453
static co_nmt_cfg_state_t * co_nmt_cfg_restore_on_enter(co_nmt_cfg_t *cfg)
The entry function of the 'restore configuration' state.
Definition: nmt_cfg.c:568
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 'SDO download confirmation' transition function of the 'store object 1F22' state.
Definition: nmt_cfg.c:846
static int co_nmt_cfg_timer(const struct timespec *tp, void *data)
The CAN timer callback function for a 'configuration request'.
Definition: nmt_cfg.c:475
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 'configuration request'.
Definition: nmt_cfg.c:487
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 'SDO download confirmation' transition function of the current state of a 'configuration ...
Definition: nmt_cfg.c:534
#define LELY_CO_NMT_CFG_RESET_TIMEOUT
The timeout (in milliseconds) after sending the NMT 'reset communication' or 'reset node' command.
Definition: nmt_cfg.c:44
static void co_nmt_cfg_store_1f20_on_leave(co_nmt_cfg_t *cfg)
The exit function of the 'store object 1F20' state.
Definition: nmt_cfg.c:789
static void co_nmt_cfg_emit_time(co_nmt_cfg_t *cfg, const struct timespec *tp)
Invokes the 'timeout' transition function of the current state of a 'configuration request'.
Definition: nmt_cfg.c:524
static void co_nmt_cfg_emit_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
Invokes the 'result received' transition function of the current state of a 'configuration request'.
Definition: nmt_cfg.c:545
This is the internal header file of the NMT 'configuration request' declarations.
This is the internal header file of the CANopen library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
A CAN network interface.
Definition: net.c:37
A CAN frame receiver.
Definition: net.c:99
A CAN timer.
Definition: net.c:63
A CANopen Client-SDO.
Definition: csdo.c:45
A CANopen device.
Definition: dev.c:41
A CANopen NMT 'configuration request' state.
Definition: nmt_cfg.c:152
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
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
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
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
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'update configuration' step completes.
Definition: nmt_cfg.c:185
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
A CANopen NMT 'configuration request' service.
Definition: nmt_cfg.c:52
co_nmt_t * nmt
A pointer to an NMT master service.
Definition: nmt_cfg.c:58
co_nmt_cfg_state_t * state
A pointer to the current state.
Definition: nmt_cfg.c:60
can_timer_t * timer
A pointer to the CAN timer.
Definition: nmt_cfg.c:64
co_unsigned32_t ac
The SDO abort code.
Definition: nmt_cfg.c:72
co_dev_t * dev
A pointer to a CANopen device.
Definition: nmt_cfg.c:56
co_unsigned32_t assignment
The NMT slave assignment (object 1F81).
Definition: nmt_cfg.c:68
co_dev_t * dev_1f20
The object dictionary stored in object 1F20 (Store DCF).
Definition: nmt_cfg.c:76
can_net_t * net
A pointer to a CAN network interface.
Definition: nmt_cfg.c:54
co_unsigned8_t id
The node-ID.
Definition: nmt_cfg.c:66
struct co_sdo_req req
The CANopen SDO upload request used for reading sub-objects.
Definition: nmt_cfg.c:74
co_unsigned32_t n_1f22
The number of entries in the concise DCF in object 1F22.
Definition: nmt_cfg.c:78
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: nmt_cfg.c:62
co_csdo_t * sdo
A pointer to the Client-SDO used to access slave objects.
Definition: nmt_cfg.c:70
A CANopen NMT master/slave service.
Definition: nmt.c:104
A CANopen object.
Definition: obj.h:32
A CANopen sub-object.
Definition: obj.h:54
A CAN or CAN FD format frame.
Definition: msg.h:87
A CANopen SDO upload/download request.
Definition: sdo.h:178
size_t offset
The offset of the bytes at buf.
Definition: sdo.h:193
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
size_t nbyte
The number of bytes available at buf.
Definition: sdo.h:188
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition: type.h:47
#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
This header file is part of the CANopen library; it contains the CANopen value declarations.
size_t co_val_read(co_unsigned16_t type, void *val, const uint_least8_t *begin, const uint_least8_t *end)
Reads a value of the specified data type from a memory buffer.
Definition: val.c:481
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