Lely core libraries  2.3.4
nmt_cfg.c
Go to the documentation of this file.
1 
24 #include "co.h"
25 
26 #if !LELY_NO_CO_MASTER && !LELY_NO_CO_NMT_CFG
27 
28 #include "nmt_cfg.h"
29 #if !LELY_NO_MALLOC
30 #include <lely/co/dcf.h>
31 #endif
32 #include <lely/co/dev.h>
33 #include <lely/co/obj.h>
34 #include <lely/co/val.h>
35 #include <lely/util/diag.h>
36 
37 #include <assert.h>
38 #if !LELY_NO_STDIO
39 #include <inttypes.h>
40 #endif
41 #include <stdlib.h>
42 
43 #ifndef LELY_CO_NMT_CFG_RESET_TIMEOUT
48 #define LELY_CO_NMT_CFG_RESET_TIMEOUT 1000
49 #endif
50 
51 struct __co_nmt_cfg_state;
53 typedef const struct __co_nmt_cfg_state co_nmt_cfg_state_t;
54 
56 struct __co_nmt_cfg {
70  co_unsigned8_t id;
72  co_unsigned32_t assignment;
76  co_unsigned32_t ac;
78  struct co_sdo_req req;
79 #if !LELY_NO_MALLOC
82 #endif
83 };
84 
90 static int co_nmt_cfg_recv(const struct can_msg *msg, void *data);
91 
97 static int co_nmt_cfg_timer(const struct timespec *tp, void *data);
98 
105 static void co_nmt_cfg_dn_con(co_csdo_t *sdo, co_unsigned16_t idx,
106  co_unsigned8_t subidx, co_unsigned32_t ac, void *data);
107 
112 static void co_nmt_cfg_enter(co_nmt_cfg_t *cfg, co_nmt_cfg_state_t *next);
113 
121 static inline void co_nmt_cfg_emit_recv(
122  co_nmt_cfg_t *cfg, const struct can_msg *msg);
123 
131 static inline void co_nmt_cfg_emit_time(
132  co_nmt_cfg_t *cfg, const struct timespec *tp);
133 
143 static inline void co_nmt_cfg_emit_dn_con(co_nmt_cfg_t *cfg,
144  co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac);
145 
153 static inline void co_nmt_cfg_emit_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac);
154 
158  co_nmt_cfg_state_t *(*on_enter)(co_nmt_cfg_t *cfg);
168  co_nmt_cfg_state_t *(*on_recv)(
169  co_nmt_cfg_t *cfg, const struct can_msg *msg);
178  co_nmt_cfg_state_t *(*on_time)(
179  co_nmt_cfg_t *cfg, const struct timespec *tp);
189  co_nmt_cfg_state_t *(*on_res)(co_nmt_cfg_t *cfg, co_unsigned32_t ac);
201  co_nmt_cfg_state_t *(*on_dn_con)(co_nmt_cfg_t *cfg, co_unsigned16_t idx,
202  co_unsigned8_t subidx, co_unsigned32_t ac);
204  void (*on_leave)(co_nmt_cfg_t *cfg);
205 };
206 
207 #define LELY_CO_DEFINE_STATE(name, ...) \
208  static co_nmt_cfg_state_t *const name = \
209  &(co_nmt_cfg_state_t){ __VA_ARGS__ };
210 
213 
214 // clang-format off
215 LELY_CO_DEFINE_STATE(co_nmt_cfg_abort_state,
216  .on_enter = &co_nmt_cfg_abort_on_enter
217 )
218 // clang-format on
219 
222 
228  co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac);
229 
230 // clang-format off
231 LELY_CO_DEFINE_STATE(co_nmt_cfg_restore_state,
232  .on_enter = &co_nmt_cfg_restore_on_enter,
233  .on_dn_con = &co_nmt_cfg_restore_on_dn_con
234 )
235 // clang-format on
236 
239 
242  co_nmt_cfg_t *cfg, const struct can_msg *msg);
243 
246  co_nmt_cfg_t *cfg, const struct timespec *tp);
247 
248 // clang-format off
249 LELY_CO_DEFINE_STATE(co_nmt_cfg_reset_state,
250  .on_enter = &co_nmt_cfg_reset_on_enter,
251  .on_recv = &co_nmt_cfg_reset_on_recv,
252  .on_time = &co_nmt_cfg_reset_on_time
253 )
254 // clang-format on
255 
256 #if !LELY_NO_MALLOC
257 
260 
266  co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac);
267 
270 
271 // clang-format off
272 LELY_CO_DEFINE_STATE(co_nmt_cfg_store_1f20_state,
273  .on_enter = &co_nmt_cfg_store_1f20_on_enter,
274  .on_dn_con = &co_nmt_cfg_store_1f20_on_dn_con,
275  .on_leave = &co_nmt_cfg_store_1f20_on_leave
276 )
277 // clang-format on
278 
281 
287  co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac);
288 
289 // clang-format off
290 LELY_CO_DEFINE_STATE(co_nmt_cfg_store_1f22_state,
291  .on_enter = &co_nmt_cfg_store_1f22_on_enter,
292  .on_dn_con = &co_nmt_cfg_store_1f22_on_dn_con
293 )
294 // clang-format on
295 
296 #endif // !LELY_NO_MALLOC
297 
300 
303  co_nmt_cfg_t *cfg, co_unsigned32_t ac);
304 
305 // clang-format off
306 LELY_CO_DEFINE_STATE(co_nmt_cfg_user_state,
307  .on_enter = &co_nmt_cfg_user_on_enter,
308  .on_res = &co_nmt_cfg_user_on_res
309 )
310 // clang-format on
311 
312 #undef LELY_CO_DEFINE_STATE
313 
314 void *
315 __co_nmt_cfg_alloc(void)
316 {
317  void *ptr = malloc(sizeof(struct __co_nmt_cfg));
318 #if !LELY_NO_ERRNO
319  if (!ptr)
320  set_errc(errno2c(errno));
321 #endif
322  return ptr;
323 }
324 
325 void
326 __co_nmt_cfg_free(void *ptr)
327 {
328  free(ptr);
329 }
330 
331 struct __co_nmt_cfg *
332 __co_nmt_cfg_init(struct __co_nmt_cfg *cfg, can_net_t *net, co_dev_t *dev,
333  co_nmt_t *nmt)
334 {
335  assert(cfg);
336  assert(net);
337  assert(dev);
338  assert(nmt);
339 
340  int errc = 0;
341 
342  cfg->net = net;
343  cfg->dev = dev;
344  cfg->nmt = nmt;
345 
346  cfg->state = NULL;
347 
348  cfg->recv = can_recv_create();
349  if (!cfg->recv) {
350  errc = get_errc();
351  goto error_create_recv;
352  }
354 
355  cfg->timer = can_timer_create();
356  if (!cfg->timer) {
357  errc = get_errc();
358  goto error_create_timer;
359  }
361 
362  cfg->id = 0;
363  cfg->assignment = 0;
364 
365  cfg->sdo = NULL;
366 
367  cfg->ac = 0;
368 
369  co_sdo_req_init(&cfg->req);
370 #if !LELY_NO_MALLOC
371  cfg->dev_1f20 = NULL;
372 #endif
373 
374  return cfg;
375 
376  // can_timer_destroy(cfg->timer);
377 error_create_timer:
378  can_recv_destroy(cfg->recv);
379 error_create_recv:
380  set_errc(errc);
381  return NULL;
382 }
383 
384 void
385 __co_nmt_cfg_fini(struct __co_nmt_cfg *cfg)
386 {
387  assert(cfg);
388 
389 #if !LELY_NO_MALLOC
390  assert(!cfg->dev_1f20);
391 #endif
392  co_sdo_req_fini(&cfg->req);
393 
394  co_csdo_destroy(cfg->sdo);
395 
396  can_timer_destroy(cfg->timer);
397  can_recv_destroy(cfg->recv);
398 }
399 
400 co_nmt_cfg_t *
402 {
403  int errc = 0;
404 
405  co_nmt_cfg_t *cfg = __co_nmt_cfg_alloc();
406  if (!cfg) {
407  errc = get_errc();
408  goto error_alloc_cfg;
409  }
410 
411  if (!__co_nmt_cfg_init(cfg, net, dev, nmt)) {
412  errc = get_errc();
413  goto error_init_cfg;
414  }
415 
416  return cfg;
417 
418 error_init_cfg:
419  __co_nmt_cfg_free(cfg);
420 error_alloc_cfg:
421  set_errc(errc);
422  return NULL;
423 }
424 
425 void
427 {
428  if (cfg) {
429  __co_nmt_cfg_fini(cfg);
430  __co_nmt_cfg_free(cfg);
431  }
432 }
433 
434 int
435 co_nmt_cfg_cfg_req(co_nmt_cfg_t *cfg, co_unsigned8_t id, int timeout,
436  co_csdo_ind_t *dn_ind, co_csdo_ind_t *up_ind, void *data)
437 {
438  assert(cfg);
439 
440  if (!id || id > CO_NUM_NODES) {
442  return -1;
443  }
444 
445  if (cfg->state) {
447  return -1;
448  }
449 
450  cfg->id = id;
451 
452  co_csdo_destroy(cfg->sdo);
453  cfg->sdo = co_csdo_create(cfg->net, NULL, cfg->id);
454  if (!cfg->sdo)
455  return -1;
456  co_csdo_set_timeout(cfg->sdo, timeout);
457  co_csdo_set_dn_ind(cfg->sdo, dn_ind, data);
458  co_csdo_set_up_ind(cfg->sdo, up_ind, data);
459 
460  co_nmt_cfg_enter(cfg, co_nmt_cfg_restore_state);
461 
462  return 0;
463 }
464 
465 int
466 co_nmt_cfg_cfg_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
467 {
468  assert(cfg);
469 
470  co_nmt_cfg_emit_res(cfg, ac);
471 
472  return 0;
473 }
474 
475 static int
476 co_nmt_cfg_recv(const struct can_msg *msg, void *data)
477 {
478  assert(msg);
479  co_nmt_cfg_t *cfg = data;
480  assert(cfg);
481 
482  co_nmt_cfg_emit_recv(cfg, msg);
483 
484  return 0;
485 }
486 
487 static int
488 co_nmt_cfg_timer(const struct timespec *tp, void *data)
489 {
490  assert(tp);
491  co_nmt_cfg_t *cfg = data;
492  assert(cfg);
493 
494  co_nmt_cfg_emit_time(cfg, tp);
495 
496  return 0;
497 }
498 
499 static void
500 co_nmt_cfg_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
501  co_unsigned32_t ac, void *data)
502 {
503  (void)sdo;
504  co_nmt_cfg_t *cfg = data;
505  assert(cfg);
506 
507  co_nmt_cfg_emit_dn_con(cfg, idx, subidx, ac);
508 }
509 
510 static void
512 {
513  assert(cfg);
514 
515  while (next) {
516  co_nmt_cfg_state_t *prev = cfg->state;
517  cfg->state = next;
518 
519  if (prev && prev->on_leave)
520  prev->on_leave(cfg);
521 
522  next = next->on_enter ? next->on_enter(cfg) : NULL;
523  }
524 }
525 
526 static inline void
527 co_nmt_cfg_emit_recv(co_nmt_cfg_t *cfg, const struct can_msg *msg)
528 {
529  assert(cfg);
530  assert(cfg->state);
531  assert(cfg->state->on_recv);
532 
533  co_nmt_cfg_enter(cfg, cfg->state->on_recv(cfg, msg));
534 }
535 
536 static inline void
537 co_nmt_cfg_emit_time(co_nmt_cfg_t *cfg, const struct timespec *tp)
538 {
539  assert(cfg);
540  assert(cfg->state);
541  assert(cfg->state->on_time);
542 
543  co_nmt_cfg_enter(cfg, cfg->state->on_time(cfg, tp));
544 }
545 
546 static inline void
547 co_nmt_cfg_emit_dn_con(co_nmt_cfg_t *cfg, co_unsigned16_t idx,
548  co_unsigned8_t subidx, co_unsigned32_t ac)
549 {
550  assert(cfg);
551  assert(cfg->state);
552  assert(cfg->state->on_dn_con);
553 
554  co_nmt_cfg_enter(cfg, cfg->state->on_dn_con(cfg, idx, subidx, ac));
555 }
556 
557 static inline void
558 co_nmt_cfg_emit_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
559 {
560  assert(cfg);
561  assert(cfg->state);
562  assert(cfg->state->on_res);
563 
564  co_nmt_cfg_enter(cfg, cfg->state->on_res(cfg, ac));
565 }
566 
567 static co_nmt_cfg_state_t *
569 {
570  assert(cfg);
571 
572  can_recv_stop(cfg->recv);
573  can_timer_stop(cfg->timer);
574 
575  co_nmt_cfg_con(cfg->nmt, cfg->id, cfg->ac);
576 
577  return NULL;
578 }
579 
580 static co_nmt_cfg_state_t *
582 {
583  assert(cfg);
584 
585  cfg->ac = 0;
586 
587  // Retrieve the slave assignment for the node.
588  cfg->assignment = co_dev_get_val_u32(cfg->dev, 0x1f81, cfg->id);
589 
590  // Abort the configuration request if the slave is not in the network
591  // list.
592  if (!(cfg->assignment & 0x01))
593  return co_nmt_cfg_abort_state;
594 
595  // Check if the slave can be used without prior resetting (bit 7).
596  if (!(cfg->assignment & 0x80))
597 #if LELY_NO_MALLOC
598  return co_nmt_cfg_user_state;
599 #else
600  return co_nmt_cfg_store_1f20_state;
601 #endif
602 
603  // Retrieve the sub-index of object 1011 of the slave that is used to
604  // initiate the restore operation.
605  co_unsigned8_t subidx = co_dev_get_val_u8(cfg->dev, 0x1f8a, cfg->id);
606 
607  // If the sub-index is 0, no restore is sent to the slave.
608  if (!subidx)
609 #if LELY_NO_MALLOC
610  return co_nmt_cfg_user_state;
611 #else
612  return co_nmt_cfg_store_1f20_state;
613 #endif
614 
615  // Write the value 'load' to sub-index of object 1011 on the slave.
616  // clang-format off
617  if (co_csdo_dn_val_req(cfg->sdo, 0x1011, subidx, CO_DEFTYPE_UNSIGNED32,
618  &(co_unsigned32_t){ UINT32_C(0x64616f6c) },
619  &co_nmt_cfg_dn_con, cfg) == -1) {
620  // clang-format on
621  cfg->ac = CO_SDO_AC_ERROR;
622  return co_nmt_cfg_abort_state;
623  }
624 
625  return NULL;
626 }
627 
628 static co_nmt_cfg_state_t *
629 co_nmt_cfg_restore_on_dn_con(co_nmt_cfg_t *cfg, co_unsigned16_t idx,
630  co_unsigned8_t subidx, co_unsigned32_t ac)
631 {
632  assert(cfg);
633  (void)idx;
634 
635  if (ac) {
636  cfg->ac = ac;
637  return co_nmt_cfg_abort_state;
638  }
639 
640  switch (subidx) {
641  case 0x02:
642  // Issue the NMT reset communication command after restoring
643  // communication related parameters.
645  break;
646  default:
647  // Issue the NMT reset node command after restoring application
648  // or manufacturer-specific parameters.
650  break;
651  }
652 
653  return co_nmt_cfg_reset_state;
654 }
655 
656 static co_nmt_cfg_state_t *
658 {
659  assert(cfg);
660 
661  // Start the CAN frame receiver for the boot-up message.
662  can_recv_start(cfg->recv, cfg->net, CO_NMT_EC_CANID(cfg->id), 0);
663  // Wait until we receive a boot-up message.
665 
666  return NULL;
667 }
668 
669 static co_nmt_cfg_state_t *
671 {
672  (void)cfg;
673  (void)msg;
674 
675  can_recv_stop(cfg->recv);
676 #if LELY_NO_MALLOC
677  return co_nmt_cfg_user_state;
678 #else
679  return co_nmt_cfg_store_1f20_state;
680 #endif
681 }
682 
683 static co_nmt_cfg_state_t *
684 co_nmt_cfg_reset_on_time(co_nmt_cfg_t *cfg, const struct timespec *tp)
685 {
686  assert(cfg);
687  (void)tp;
688 
689  cfg->ac = CO_SDO_AC_TIMEOUT;
690  return co_nmt_cfg_abort_state;
691 }
692 
693 #if !LELY_NO_MALLOC
694 
695 static co_nmt_cfg_state_t *
697 {
698 #if LELY_NO_CO_DCF
699  (void)cfg;
700 
701  return co_nmt_cfg_store_1f22_state;
702 #else // !LELY_NO_CO_DCF
703  assert(cfg);
704 
705  // Check if the DCF is available and the format is plain ASCII.
706  co_sub_t *sub = co_dev_find_sub(cfg->dev, 0x1f20, cfg->id);
707  if (!sub || co_dev_get_val_u8(cfg->dev, 0x1f21, cfg->id) != 0)
708  return co_nmt_cfg_store_1f22_state;
709 
710  // Upload the DCF.
711  struct co_sdo_req *req = &cfg->req;
712  co_sdo_req_clear(req);
713  cfg->ac = co_sub_up_ind(sub, req);
714  if (cfg->ac) {
715 #if !LELY_NO_STDIO
716  diag(DIAG_ERROR, 0,
717  "SDO abort code %08" PRIX32
718  " on upload request of object 1F20:%02X (Store DCF): %s",
719  cfg->ac, cfg->id, co_sdo_ac2str(cfg->ac));
720 #endif
721  return co_nmt_cfg_abort_state;
722  }
723 
724  if (!co_sdo_req_first(req) || !co_sdo_req_last(req)) {
725 #if !LELY_NO_STDIO
726  diag(DIAG_WARNING, 0,
727  "object 1F20:%02X (Store DCF) unusable for configuration request",
728  cfg->id);
729 #endif
730  return co_nmt_cfg_store_1f22_state;
731  }
732 
733  // Ignore an empty DCF.
734  if (!req->nbyte)
735  return co_nmt_cfg_store_1f22_state;
736 
737  // Parse the DCF.
738  assert(!cfg->dev_1f20);
740  req->buf, (const char *)req->buf + req->nbyte, NULL);
741  if (!cfg->dev_1f20) {
742  cfg->ac = CO_SDO_AC_ERROR;
743  return co_nmt_cfg_abort_state;
744  }
745 
746  return co_nmt_cfg_store_1f20_on_dn_con(cfg, 0, 0, 0);
747 #endif // !LELY_NO_CO_DCF
748 }
749 
750 static co_nmt_cfg_state_t *
752  co_unsigned8_t subidx, co_unsigned32_t ac)
753 {
754  assert(cfg);
755  assert(cfg->dev_1f20);
756 
757  if (ac) {
758  cfg->ac = ac;
759  return co_nmt_cfg_abort_state;
760  }
761 
762  // Find the next (or first) sub-object in the object dictionary.
763  co_obj_t *obj;
764  co_sub_t *sub;
765  if (idx) {
766  obj = co_dev_find_obj(cfg->dev_1f20, idx);
767  assert(obj);
768  sub = co_obj_find_sub(obj, subidx);
769  assert(sub);
770  sub = co_sub_next(sub);
771  } else {
772  obj = co_dev_first_obj(cfg->dev_1f20);
773  if (!obj)
774  return co_nmt_cfg_store_1f22_state;
775  sub = co_obj_first_sub(obj);
776  }
777 
778  // Find the next sub-object to be written.
779  co_unsigned16_t type;
780  const void *val;
781  for (;; sub = co_sub_next(sub)) {
782  while (!sub) {
783  obj = co_obj_next(obj);
784  if (!obj)
785  return co_nmt_cfg_store_1f22_state;
786  sub = co_obj_first_sub(obj);
787  }
788  // Skip read-only sub-objects.
789  if (!(co_sub_get_access(sub) & CO_ACCESS_WRITE))
790  continue;
791  // Skip file-based sub-objects.
793  continue;
794  // Skip sub-objects containing the default value.
795  type = co_sub_get_type(sub);
796  val = co_sub_get_val(sub);
797 #if !LELY_NO_CO_OBJ_DEFAULT
798  const void *def = co_sub_get_def(sub);
799  if (!co_val_cmp(type, def, val))
800  continue;
801 #endif
802  break;
803  }
804 
805  // Write the value to the slave.
806  idx = co_obj_get_idx(obj);
807  subidx = co_sub_get_subidx(sub);
808  // clang-format off
809  if (co_csdo_dn_val_req(cfg->sdo, idx, subidx, type, val,
810  &co_nmt_cfg_dn_con, cfg) == -1) {
811  // clang-format on
812  cfg->ac = CO_SDO_AC_ERROR;
813  return co_nmt_cfg_abort_state;
814  }
815 
816  return NULL;
817 }
818 
819 static void
821 {
822  assert(cfg);
823 
824  co_dev_destroy(cfg->dev_1f20);
825  cfg->dev_1f20 = NULL;
826 }
827 
828 static co_nmt_cfg_state_t *
830 {
831  assert(cfg);
832 
833  co_sub_t *sub = co_dev_find_sub(cfg->dev, 0x1f22, cfg->id);
834  if (!sub)
835  return co_nmt_cfg_user_state;
836 
837  // Upload the concise DCF.
838  struct co_sdo_req *req = &cfg->req;
839  co_sdo_req_clear(req);
840  cfg->ac = co_sub_up_ind(sub, req);
841  if (cfg->ac) {
842 #if !LELY_NO_STDIO
843  diag(DIAG_ERROR, 0,
844  "SDO abort code %08" PRIX32
845  " on upload request of object 1F22:%02X (Concise DCF): %s",
846  cfg->ac, cfg->id, co_sdo_ac2str(cfg->ac));
847 #endif
848  return co_nmt_cfg_abort_state;
849  }
850 
851  if (!co_sdo_req_first(req) || !co_sdo_req_last(req)) {
852  diag(DIAG_WARNING, 0,
853  "object 1F22:%02X (Concise DCF) unusable for configuration request",
854  cfg->id);
855  return co_nmt_cfg_user_state;
856  }
857 
858  // Ignore an empty concise DCF.
859  if (!req->nbyte)
860  return co_nmt_cfg_user_state;
861 
862  // Submit download requests for all entries in the concise DCF.
863  const uint_least8_t *begin = req->buf;
864  const uint_least8_t *end = begin + req->nbyte;
865  if (co_csdo_dn_dcf_req(cfg->sdo, begin, end, &co_nmt_cfg_dn_con, cfg)
866  == -1) {
867  cfg->ac = CO_SDO_AC_ERROR;
868  return co_nmt_cfg_abort_state;
869  }
870 
871  return NULL;
872 }
873 
874 static co_nmt_cfg_state_t *
876  co_unsigned8_t subidx, co_unsigned32_t ac)
877 {
878  assert(cfg);
879  (void)idx;
880  (void)subidx;
881 
882  if (ac) {
883  cfg->ac = ac;
884  return co_nmt_cfg_abort_state;
885  }
886 
887  return co_nmt_cfg_user_state;
888 }
889 
890 #endif // !LELY_NO_MALLOC
891 
892 static co_nmt_cfg_state_t *
894 {
895  assert(cfg);
896 
897  co_nmt_cfg_ind(cfg->nmt, cfg->id, cfg->sdo);
898 
899  return NULL;
900 }
901 
902 static co_nmt_cfg_state_t *
903 co_nmt_cfg_user_on_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
904 {
905  assert(cfg);
906 
907  cfg->ac = ac;
908  return co_nmt_cfg_abort_state;
909 }
910 
911 #endif // !LELY_NO_CO_MASTER && !LELY_NO_CO_NMT_CFG
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:290
#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:297
void co_dev_destroy(co_dev_t *dev)
Destroys a CANopen device, including all objects in its object dictionary.
Definition: dev.c:163
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_csdo_t * co_csdo_create(can_net_t *net, co_dev_t *dev, co_unsigned8_t num)
Creates a new CANopen Client-SDO service.
Definition: csdo.c:997
void co_csdo_set_timeout(co_csdo_t *sdo, int timeout)
Sets the timeout of a Client-SDO.
Definition: csdo.c:1142
void co_csdo_set_up_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO upload reques...
Definition: csdo.c:1184
int co_csdo_dn_dcf_req(co_csdo_t *sdo, const uint_least8_t *begin, const uint_least8_t *end, co_csdo_dn_con_t *con, void *data)
Submits a series of download requests to a remote Server-SDO.
Definition: csdo.c:1265
void co_csdo_ind_t(const co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
The type of a CANopen Client-SDO request progress indication function, used to notify the user of the...
Definition: csdo.h:79
void co_csdo_set_dn_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO download requ...
Definition: csdo.c:1164
int co_csdo_dn_val_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned16_t type, const void *val, co_csdo_dn_con_t *con, void *data)
Submits a download request to a remote Server-SDO.
Definition: csdo.c:1241
void co_csdo_destroy(co_csdo_t *sdo)
Destroys a CANopen Client-SDO service.
Definition: csdo.c:1024
This header file is part of the 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:55
@ DIAG_ERROR
An error.
Definition: diag.h:57
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:171
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:132
@ ERRNUM_INPROGRESS
Operation in progress.
Definition: errnum.h:128
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:932
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:944
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:46
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:424
int co_sdo_req_first(const struct co_sdo_req *req)
Returns 1 if the specified request includes the first segment, and 0 otherwise.
Definition: sdo.h:343
void co_sdo_req_fini(struct co_sdo_req *req)
Finalizes a CANopen SDO upload/download request.
Definition: sdo.c:121
#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:349
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:462
void can_timer_set_func(can_timer_t *timer, can_timer_func_t *func, void *data)
Sets the callback function invoked when a CAN timer is triggered.
Definition: net.c:422
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition: net.c:533
void can_recv_stop(can_recv_t *recv)
Stops a CAN frame receiver from processing frames and unregisters it with the network interface.
Definition: net.c:609
void can_recv_set_func(can_recv_t *recv, can_recv_func_t *func, void *data)
Sets the callback function used to process CAN frames with a receiver.
Definition: net.c:578
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition: net.c:558
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition: net.c:376
void can_timer_timeout(can_timer_t *timer, can_net_t *net, int timeout)
Starts a CAN timer and registers it with a network interface.
Definition: net.c:478
void can_recv_start(can_recv_t *recv, can_net_t *net, uint_least32_t id, uint_least8_t flags)
Registers a CAN frame receiver with a network interface and starts processing frames.
Definition: net.c:587
void can_timer_destroy(can_timer_t *timer)
Destroys a CAN timer.
Definition: net.c:401
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:2375
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:2389
#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:1806
#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:751
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:829
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:511
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:568
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:670
void co_nmt_cfg_destroy(co_nmt_cfg_t *cfg)
Destroys a CANopen NMT 'configuration request'.
Definition: nmt_cfg.c:426
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:893
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:657
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:435
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:696
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:476
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:401
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:903
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:629
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:684
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:527
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:466
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:581
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:875
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:488
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:500
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:547
#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:48
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:820
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:537
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:558
This is the internal header file of the NMT 'configuration request' declarations.
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:559
const void * co_sub_get_val(const co_sub_t *sub)
Returns a pointer to the current value of a CANopen sub-object.
Definition: obj.c:712
co_sub_t * co_sub_next(const co_sub_t *sub)
Finds the next sub-object in a CANopen object.
Definition: obj.c:542
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition: obj.c:164
co_unsigned32_t co_sub_up_ind(const co_sub_t *sub, struct co_sdo_req *req)
Invokes the upload indication function of a CANopen sub-object, registered with co_sub_set_up_ind().
Definition: obj.c:1066
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:683
unsigned int co_sub_get_flags(const co_sub_t *sub)
Returns the object flags of a CANopen sub-object.
Definition: obj.c:818
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:147
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:240
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:249
#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:778
co_unsigned16_t co_sub_get_type(const co_sub_t *sub)
Returns the data type of a CANopen sub-object.
Definition: obj.c:603
This is the internal header file of the CANopen library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
A CAN network interface.
Definition: net.c:37
A CAN frame receiver.
Definition: net.c:86
A CAN timer.
Definition: net.c:63
A CANopen Client-SDO.
Definition: csdo.c:71
A CANopen device.
Definition: dev.h:30
A CANopen NMT 'configuration request' state.
Definition: nmt_cfg.c:156
void(* on_leave)(co_nmt_cfg_t *cfg)
A pointer to the function invoked when the current state is left.
Definition: nmt_cfg.c:204
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:158
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:178
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:168
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:189
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:201
A CANopen NMT 'configuration request' service.
Definition: nmt_cfg.c:56
co_nmt_t * nmt
A pointer to an NMT master service.
Definition: nmt_cfg.c:62
co_nmt_cfg_state_t * state
A pointer to the current state.
Definition: nmt_cfg.c:64
can_timer_t * timer
A pointer to the CAN timer.
Definition: nmt_cfg.c:68
co_unsigned32_t ac
The SDO abort code.
Definition: nmt_cfg.c:76
co_dev_t * dev
A pointer to a CANopen device.
Definition: nmt_cfg.c:60
co_unsigned32_t assignment
The NMT slave assignment (object 1F81).
Definition: nmt_cfg.c:72
co_dev_t * dev_1f20
The object dictionary stored in object 1F20 (Store DCF).
Definition: nmt_cfg.c:81
can_net_t * net
A pointer to a CAN network interface.
Definition: nmt_cfg.c:58
co_unsigned8_t id
The node-ID.
Definition: nmt_cfg.c:70
struct co_sdo_req req
The CANopen SDO upload request used for reading sub-objects.
Definition: nmt_cfg.c:78
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: nmt_cfg.c:66
co_csdo_t * sdo
A pointer to the Client-SDO used to access slave objects.
Definition: nmt_cfg.c:74
A CANopen NMT master/slave service.
Definition: nmt.c:148
A CANopen object.
Definition: obj.h:31
A CANopen sub-object.
Definition: obj.h:53
A CAN or CAN FD format frame.
Definition: msg.h:87
A CANopen SDO upload/download request.
Definition: sdo.h:181
const void * buf
A pointer to the next bytes to be uploaded/downloaded.
Definition: sdo.h:189
size_t nbyte
The number of bytes available at buf.
Definition: sdo.h:191
#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.
int co_val_cmp(co_unsigned16_t type, const void *v1, const void *v2)
Compares two values of the specified data type.
Definition: val.c:369