Lely core libraries  1.9.2
gw.c
Go to the documentation of this file.
1 
24 #include "co.h"
25 
26 #ifndef LELY_NO_CO_GW
27 
28 #include <lely/co/csdo.h>
29 #include <lely/co/dev.h>
30 #include <lely/util/errnum.h>
31 #ifndef LELY_NO_CO_EMCY
32 #include <lely/co/emcy.h>
33 #endif
34 #include <lely/co/gw.h>
35 #if !defined(LELY_NO_CO_MASTER) && !defined(LELY_NO_CO_LSS)
36 #include <lely/co/lss.h>
37 #endif
38 #include <lely/co/nmt.h>
39 #include <lely/co/obj.h>
40 #ifndef LELY_NO_CO_RPDO
41 #include <lely/co/rpdo.h>
42 #endif
43 #include <lely/co/sdo.h>
44 #ifndef LELY_NO_CO_SYNC
45 #include <lely/co/sync.h>
46 #endif
47 #ifndef LELY_NO_CO_TIME
48 #include <lely/co/time.h>
49 #endif
50 #ifndef LELY_NO_CO_TPDO
51 #include <lely/co/tpdo.h>
52 #endif
53 
54 #include <assert.h>
55 #include <stdlib.h>
56 
57 struct co_gw_job;
58 
60 struct co_gw_net {
64  co_unsigned16_t id;
68  co_unsigned8_t def;
69 #ifndef LELY_NO_CO_CSDO
70  int timeout;
72 #endif
73 
77  unsigned bootup_ind : 1;
78 #ifndef LELY_NO_CO_CSDO
79  struct co_gw_job *sdo[CO_NUM_NODES];
81 #endif
82 #if !defined(LELY_NO_CO_MASTER) && !defined(LELY_NO_CO_LSS)
83  struct co_gw_job *lss;
85 #endif
89  void *cs_data;
90 #ifndef LELY_NO_CO_MASTER
94  void *ng_data;
95 #endif
99  void *lg_data;
103  void *hb_data;
107  void *st_data;
108 #ifndef LELY_NO_CO_MASTER
112  void *boot_data;
116  void *dn_data;
120  void *up_data;
121 #endif
122 };
123 
125 static struct co_gw_net *co_gw_net_create(
126  co_gw_t *gw, co_unsigned16_t id, co_nmt_t *nmt);
127 
129 static void co_gw_net_destroy(struct co_gw_net *net);
130 
137 static void co_gw_net_cs_ind(co_nmt_t *nmt, co_unsigned8_t cs, void *data);
138 #ifndef LELY_NO_CO_MASTER
139 
145 static void co_gw_net_ng_ind(co_nmt_t *nmt, co_unsigned8_t id, int state,
146  int reason, void *data);
147 #endif
148 
154 static void co_gw_net_lg_ind(co_nmt_t *nmt, int state, void *data);
161 static void co_gw_net_hb_ind(co_nmt_t *nmt, co_unsigned8_t id, int state,
162  int reason, void *data);
169 static void co_gw_net_st_ind(co_nmt_t *nmt, co_unsigned8_t id,
170  co_unsigned8_t st, void *data);
171 #ifndef LELY_NO_CO_MASTER
172 
178 static void co_gw_net_boot_ind(co_nmt_t *nmt, co_unsigned8_t id,
179  co_unsigned8_t st, char es, void *data);
187 static void co_gw_net_dn_ind(co_nmt_t *nmt, co_unsigned8_t id,
188  co_unsigned16_t idx, co_unsigned8_t subidx, size_t size,
189  size_t nbyte, void *data);
197 static void co_gw_net_up_ind(co_nmt_t *nmt, co_unsigned8_t id,
198  co_unsigned16_t idx, co_unsigned8_t subidx, size_t size,
199  size_t nbyte, void *data);
200 #endif
201 #ifndef LELY_NO_CO_SYNC
202 
206 static void co_gw_net_sync_ind(co_sync_t *sync, co_unsigned8_t cnt, void *data);
207 #endif
208 #ifndef LELY_NO_CO_TIME
209 
213 static void co_gw_net_time_ind(
214  co_time_t *time, const struct timespec *tp, void *data);
215 #endif
216 #ifndef LELY_NO_CO_EMCY
217 
221 static void co_gw_net_emcy_ind(co_emcy_t *emcy, co_unsigned8_t id,
222  co_unsigned16_t ec, co_unsigned8_t er, uint8_t msef[5],
223  void *data);
224 #endif
225 #ifndef LELY_NO_CO_RPDO
226 
230 static void co_gw_net_rpdo_ind(co_rpdo_t *pdo, co_unsigned32_t ac,
231  const void *ptr, size_t n, void *data);
232 #endif
233 
235 struct co_gw_job {
237  struct co_gw_job **pself;
239  struct co_gw_net *net;
241  void *data;
243  void (*dtor)(void *data);
245  struct co_gw_req req;
246 };
247 
249 #define CO_GW_JOB_SIZE offsetof(struct co_gw_job, req)
250 
252 static struct co_gw_job *co_gw_job_create(struct co_gw_job **pself,
253  struct co_gw_net *net, void *data, void (*dtor)(void *data),
254  const struct co_gw_req *req);
256 static void co_gw_job_destroy(struct co_gw_job *job);
257 
259 static void co_gw_job_remove(struct co_gw_job *job);
260 
261 #ifndef LELY_NO_CO_CSDO
262 static struct co_gw_job *co_gw_job_create_sdo(struct co_gw_job **pself,
264  struct co_gw_net *net, co_unsigned8_t id,
265  const struct co_gw_req *req);
267 static void co_gw_job_sdo_dtor(void *data);
269 static void co_gw_job_sdo_up_con(co_csdo_t *sdo, co_unsigned16_t idx,
270  co_unsigned8_t subidx, co_unsigned32_t ac, const void *ptr,
271  size_t n, void *data);
273 static void co_gw_job_sdo_dn_con(co_csdo_t *sdo, co_unsigned16_t idx,
274  co_unsigned8_t subidx, co_unsigned32_t ac, void *data);
276 static void co_gw_job_sdo_ind(const co_csdo_t *sdo, co_unsigned16_t idx,
277  co_unsigned8_t subidx, size_t size, size_t nbyte, void *data);
278 #endif
279 
280 #if !defined(LELY_NO_CO_MASTER) && !defined(LELY_NO_CO_LSS)
281 static struct co_gw_job *co_gw_job_create_lss(struct co_gw_job **pself,
283  struct co_gw_net *net, const struct co_gw_req *req);
288 static void co_gw_job_lss_cs_ind(co_lss_t *lss, co_unsigned8_t cs, void *data);
293 static void co_gw_job_lss_err_ind(co_lss_t *lss, co_unsigned8_t cs,
294  co_unsigned8_t err, co_unsigned8_t spec, void *data);
296 static void co_gw_job_lss_lssid_ind(co_lss_t *lss, co_unsigned8_t cs,
297  co_unsigned32_t id, void *data);
299 static void co_gw_job_lss_nid_ind(co_lss_t *lss, co_unsigned8_t cs,
300  co_unsigned8_t id, void *data);
302 static void co_gw_job_lss_scan_ind(co_lss_t *lss, co_unsigned8_t cs,
303  const struct co_id *id, void *data);
304 #endif
305 
307 struct __co_gw {
311  int timeout;
313  co_unsigned16_t def;
320  void *send_data;
327  void *rate_data;
328 };
329 
330 #ifndef LELY_NO_CO_CSDO
331 static int co_gw_recv_sdo_up(co_gw_t *gw, co_unsigned16_t net,
333  co_unsigned8_t node, const struct co_gw_req *req);
335 static int co_gw_recv_sdo_dn(co_gw_t *gw, co_unsigned16_t net,
336  co_unsigned8_t node, const struct co_gw_req *req);
338 static int co_gw_recv_set_sdo_timeout(
339  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
340 #endif
341 
342 #ifndef LELY_NO_CO_RPDO
343 static int co_gw_recv_set_rpdo(
345  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
346 #endif
347 #ifndef LELY_NO_CO_TPDO
348 static int co_gw_recv_set_tpdo(
350  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
351 #endif
352 #ifndef LELY_NO_CO_RPDO
353 static int co_gw_recv_pdo_read(
355  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
356 #endif
357 #ifndef LELY_NO_CO_TPDO
358 static int co_gw_recv_pdo_write(
360  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
361 #endif
362 
363 #ifndef LELY_NO_CO_MASTER
364 static int co_gw_recv_nmt_cs(co_gw_t *gw, co_unsigned16_t net,
366  co_unsigned8_t node, co_unsigned8_t cs,
367  const struct co_gw_req *req);
369 static int co_gw_recv_nmt_set_ng(co_gw_t *gw, co_unsigned16_t net,
370  co_unsigned8_t node, const struct co_gw_req *req);
371 #endif
372 static int co_gw_recv_nmt_set_hb(co_gw_t *gw, co_unsigned16_t net,
374  co_unsigned8_t node, const struct co_gw_req *req);
375 
377 static int co_gw_recv_init(
378  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
380 static int co_gw_recv_set_hb(
381  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
383 static int co_gw_recv_set_id(
384  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
385 #ifndef LELY_NO_CO_EMCY
386 static int co_gw_recv_set_emcy(co_gw_t *gw, co_unsigned16_t net,
388  co_unsigned8_t node, const struct co_gw_req *req);
389 #endif
390 static int co_gw_recv_set_cmd_timeout(co_gw_t *gw, const struct co_gw_req *req);
393 static int co_gw_recv_set_bootup_ind(
394  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
395 
397 static int co_gw_recv_set_net(co_gw_t *gw, const struct co_gw_req *req);
399 static int co_gw_recv_set_node(
400  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
402 static int co_gw_recv_get_version(
403  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
404 
405 #if !defined(LELY_NO_CO_MASTER) && !defined(LELY_NO_CO_LSS)
406 static int co_gw_recv_lss_switch(
408  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
410 static int co_gw_recv_lss_switch_sel(
411  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
413 static int co_gw_recv_lss_set_id(
414  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
416 static int co_gw_recv_lss_set_rate(
417  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
419 static int co_gw_recv_lss_switch_rate(
420  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
422 static int co_gw_recv_lss_store(
423  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
425 static int co_gw_recv_lss_get_lssid(
426  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
428 static int co_gw_recv_lss_get_id(
429  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
431 static int co_gw_recv_lss_id_slave(
432  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
435  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
436 
438 static int co_gw_recv__lss_slowscan(
439  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
441 static int co_gw_recv__lss_fastscan(
442  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
443 #endif
444 
446 static int co_gw_send_con(co_gw_t *gw, const struct co_gw_req *req, int iec,
447  co_unsigned32_t ac);
449 static int co_gw_send_ec(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
450  co_unsigned8_t st, int iec);
452 static int co_gw_send_srv(co_gw_t *gw, const struct co_gw_srv *srv);
453 
455 static inline int errnum2iec(errnum_t errnum);
456 
457 const char *
459 {
460  switch (iec) {
461  case CO_GW_IEC_BAD_SRV: return "Request not supported";
462  case CO_GW_IEC_SYNTAX: return "Syntax error";
463  case CO_GW_IEC_INTERN:
464  return "Request not processed due to internal state";
465  case CO_GW_IEC_TIMEOUT: return "Time-out";
466  case CO_GW_IEC_NO_DEF_NET: return "No default net set";
467  case CO_GW_IEC_NO_DEF_NODE: return "No default node set";
468  case CO_GW_IEC_BAD_NET: return "Unsupported net";
469  case CO_GW_IEC_BAD_NODE: return "Unsupported node";
470  case CO_GW_IEC_NG_OCCURRED: return "Lost guarding message";
471  case CO_GW_IEC_LG_OCCURRED: return "Lost connection";
472  case CO_GW_IEC_HB_RESOLVED: return "Heartbeat started";
473  case CO_GW_IEC_HB_OCCURRED: return "Heartbeat lost";
474  case CO_GW_IEC_ST_OCCURRED: return "Wrong NMT state";
475  case CO_GW_IEC_BOOTUP: return "Boot-up";
476  case CO_GW_IEC_CAN_PASSIVE: return "Error passive";
477  case CO_GW_IEC_CAN_BUSOFF: return "Bus off";
478  case CO_GW_IEC_CAN_OVERFLOW: return "CAN buffer overflow";
479  case CO_GW_IEC_CAN_INIT: return "CAN init";
480  case CO_GW_IEC_CAN_ACTIVE: return "CAN active";
481  case CO_GW_IEC_PDO_INUSE: return "PDO already used";
482  case CO_GW_IEC_PDO_LEN: return "PDO length exceeded";
483  case CO_GW_IEC_LSS: return "LSS error";
484  case CO_GW_IEC_LSS_ID: return "LSS node-ID not supported";
485  case CO_GW_IEC_LSS_RATE: return "LSS bit-rate not supported";
486  case CO_GW_IEC_LSS_PARAM: return "LSS parameter storing failed";
487  case CO_GW_IEC_LSS_MEDIA:
488  return "LSS command failed because of media error";
489  case CO_GW_IEC_NO_MEM: return "Running out of memory";
490  default: return "Unknown error code";
491  }
492 }
493 
494 void *
495 __co_gw_alloc(void)
496 {
497  void *ptr = malloc(sizeof(struct __co_gw));
498  if (__unlikely(!ptr))
499  set_errc(errno2c(errno));
500  return ptr;
501 }
502 
503 void
504 __co_gw_free(void *ptr)
505 {
506  free(ptr);
507 }
508 
509 struct __co_gw *
510 __co_gw_init(struct __co_gw *gw)
511 {
512  assert(gw);
513 
514  for (co_unsigned16_t id = 1; id <= CO_GW_NUM_NET; id++)
515  gw->net[id - 1] = NULL;
516 
517  gw->timeout = 0;
518  gw->def = 0;
519 
520  gw->send_func = NULL;
521  gw->send_data = NULL;
522 
523  gw->rate_func = NULL;
524  gw->rate_data = NULL;
525 
526  return gw;
527 }
528 
529 void
530 __co_gw_fini(struct __co_gw *gw)
531 {
532  assert(gw);
533 
534  for (co_unsigned16_t id = 1; id <= CO_GW_NUM_NET; id++)
535  co_gw_net_destroy(gw->net[id - 1]);
536 }
537 
538 co_gw_t *
540 {
541  int errc = 0;
542 
543  co_gw_t *gw = __co_gw_alloc();
544  if (__unlikely(!gw)) {
545  errc = get_errc();
546  goto error_alloc_gw;
547  }
548 
549  if (__unlikely(!__co_gw_init(gw))) {
550  errc = get_errc();
551  goto error_init_gw;
552  }
553 
554  return gw;
555 
556 error_init_gw:
557  __co_gw_free(gw);
558 error_alloc_gw:
559  set_errc(errc);
560  return NULL;
561 }
562 
563 void
565 {
566  if (gw) {
567  __co_gw_fini(gw);
568  __co_gw_free(gw);
569  }
570 }
571 
572 int
573 co_gw_init_net(co_gw_t *gw, co_unsigned16_t id, co_nmt_t *nmt)
574 {
575  assert(gw);
576 
577  if (!id)
578  id = co_dev_get_netid(co_nmt_get_dev(nmt));
579 
580  if (__unlikely(co_gw_fini_net(gw, id) == -1))
581  return -1;
582 
583  gw->net[id - 1] = co_gw_net_create(gw, id, nmt);
584  return __likely(gw->net[id - 1]) ? 0 : -1;
585 }
586 
587 int
588 co_gw_fini_net(co_gw_t *gw, co_unsigned16_t id)
589 {
590  assert(gw);
591 
592  if (__unlikely(!id || id > CO_GW_NUM_NET)) {
594  return -1;
595  }
596 
597  co_gw_net_destroy(gw->net[id - 1]);
598  gw->net[id - 1] = NULL;
599 
600  return 0;
601 }
602 
603 int
604 co_gw_recv(co_gw_t *gw, const struct co_gw_req *req)
605 {
606  assert(gw);
607  assert(req);
608 
609  if (__unlikely(req->size < sizeof(*req))) {
611  return -1;
612  }
613 
614  int iec = 0;
615 
616  // Obtain the network-ID for node- and network-level requests. If the
617  // network-ID is 0, use the default ID.
618  co_unsigned16_t net = gw->def;
619  switch (req->srv) {
620 #ifndef LELY_NO_CO_CSDO
621  case CO_GW_SRV_SDO_UP:
622  case CO_GW_SRV_SDO_DN:
624 #endif
625 #ifndef LELY_NO_CO_RPDO
626  case CO_GW_SRV_SET_RPDO:
627 #endif
628 #ifndef LELY_NO_CO_TPDO
629  case CO_GW_SRV_SET_TPDO:
630 #endif
631 #ifndef LELY_NO_CO_RPDO
632  case CO_GW_SRV_PDO_READ:
633 #endif
634 #ifndef LELY_NO_CO_TPDO
635  case CO_GW_SRV_PDO_WRITE:
636 #endif
637 #ifndef LELY_NO_CO_MASTER
638  case CO_GW_SRV_NMT_START:
639  case CO_GW_SRV_NMT_STOP:
645 #endif
648  case CO_GW_SRV_INIT:
649  case CO_GW_SRV_SET_HB:
650  case CO_GW_SRV_SET_ID:
651 #ifndef LELY_NO_CO_EMCY
653  case CO_GW_SRV_EMCY_STOP:
654 #endif
656  case CO_GW_SRV_SET_NODE:
658 #if !defined(LELY_NO_CO_MASTER) && !defined(LELY_NO_CO_LSS)
664  case CO_GW_SRV_LSS_STORE:
671 #endif
672  if (__unlikely(req->size < sizeof(struct co_gw_req_net))) {
674  return -1;
675  }
676  struct co_gw_req_net *par = (struct co_gw_req_net *)req;
677  if (par->net)
678  net = par->net;
679  if (__unlikely(!net)) {
680  iec = CO_GW_IEC_NO_DEF_NET;
681  goto error;
682  // clang-format off
683  } else if (__unlikely(net > CO_GW_NUM_NET
684  || !gw->net[net - 1])) {
685  // clang-format on
686  iec = CO_GW_IEC_BAD_NET;
687  goto error;
688  }
689  break;
690  }
691  assert(net <= CO_GW_NUM_NET);
692  assert(!net || gw->net[net - 1]);
693 
694  // Obtain the node-ID for node-level requests. If the node-ID is 0xff,
695  // use the default ID.
696  co_unsigned8_t node = net ? gw->net[net - 1]->def : 0;
697  switch (req->srv) {
698 #ifndef LELY_NO_CO_CSDO
699  case CO_GW_SRV_SDO_UP:
700  case CO_GW_SRV_SDO_DN:
701 #endif
702 #ifndef LELY_NO_CO_MASTER
703  case CO_GW_SRV_NMT_START:
704  case CO_GW_SRV_NMT_STOP:
710 #endif
713 #ifndef LELY_NO_CO_EMCY
715  case CO_GW_SRV_EMCY_STOP:
716 #endif
717  if (__unlikely(req->size < sizeof(struct co_gw_req_node))) {
719  return -1;
720  }
721  struct co_gw_req_node *par = (struct co_gw_req_node *)req;
722  if (par->node != 0xff)
723  node = par->node;
724  if (__unlikely(node > CO_NUM_NODES)) {
725  iec = CO_GW_IEC_BAD_NODE;
726  goto error;
727  }
728  break;
729  }
730 
731  // Except for the NMT commands, node-level request require a non-zero
732  // node-ID.
733  switch (req->srv) {
734 #ifndef LELY_NO_CO_CSDO
735  case CO_GW_SRV_SDO_UP:
736  case CO_GW_SRV_SDO_DN:
737 #endif
738 #ifndef LELY_NO_CO_MASTER
741 #endif
744 #ifndef LELY_NO_CO_EMCY
746  case CO_GW_SRV_EMCY_STOP:
747 #endif
748  if (__unlikely(!node)) {
749  iec = CO_GW_IEC_NO_DEF_NODE;
750  goto error;
751  }
752  }
753 
754  switch (req->srv) {
755 #ifndef LELY_NO_CO_CSDO
756  case CO_GW_SRV_SDO_UP:
757  trace("gateway: received 'SDO upload' request");
758  return co_gw_recv_sdo_up(gw, net, node, req);
759  case CO_GW_SRV_SDO_DN:
760  trace("gateway: received 'SDO download' request");
761  return co_gw_recv_sdo_dn(gw, net, node, req);
763  trace("gateway: received 'Configure SDO time-out' request");
764  return co_gw_recv_set_sdo_timeout(gw, net, req);
765 #endif
766 #ifndef LELY_NO_CO_RPDO
767  case CO_GW_SRV_SET_RPDO:
768  trace("gateway: received 'Configure RPDO' request");
769  return co_gw_recv_set_rpdo(gw, net, req);
770 #endif
771 #ifndef LELY_NO_CO_TPDO
772  case CO_GW_SRV_SET_TPDO:
773  trace("gateway: received 'Configure TPDO' request");
774  return co_gw_recv_set_tpdo(gw, net, req);
775 #endif
776 #ifndef LELY_NO_CO_RPDO
777  case CO_GW_SRV_PDO_READ:
778  trace("gateway: received 'Read PDO data' request");
779  return co_gw_recv_pdo_read(gw, net, req);
780 #endif
781 #ifndef LELY_NO_CO_TPDO
782  case CO_GW_SRV_PDO_WRITE:
783  trace("gateway: received 'Write PDO data' request");
784  return co_gw_recv_pdo_write(gw, net, req);
785 #endif
786 #ifndef LELY_NO_CO_MASTER
787  case CO_GW_SRV_NMT_START:
788  trace("gateway: received 'Start node' request");
789  return co_gw_recv_nmt_cs(gw, net, node, CO_NMT_CS_START, req);
790  case CO_GW_SRV_NMT_STOP:
791  trace("gateway: received 'Stop node' request");
792  return co_gw_recv_nmt_cs(gw, net, node, CO_NMT_CS_STOP, req);
794  trace("gateway: received 'Set node to pre-operational' request");
795  return co_gw_recv_nmt_cs(
796  gw, net, node, CO_NMT_CS_ENTER_PREOP, req);
798  trace("gateway: received 'Reset node' request");
799  return co_gw_recv_nmt_cs(
800  gw, net, node, CO_NMT_CS_RESET_NODE, req);
802  trace("gateway: received 'Reset communication' request");
803  return co_gw_recv_nmt_cs(
804  gw, net, node, CO_NMT_CS_RESET_COMM, req);
807  trace("gateway: received '%s node guarding' request",
809  ? "Enable"
810  : "Disable");
811  return co_gw_recv_nmt_set_ng(gw, net, node, req);
812 #endif
815  trace("gateway: received '%s heartbeat consumer' request",
817  ? "Start"
818  : "Disable");
819  return co_gw_recv_nmt_set_hb(gw, net, node, req);
820  case CO_GW_SRV_INIT:
821  trace("gateway: received 'Initialize gateway' request");
822  return co_gw_recv_init(gw, net, req);
823  case CO_GW_SRV_SET_HB:
824  trace("gateway: received 'Set heartbeat producer' request");
825  return co_gw_recv_set_hb(gw, net, req);
826  case CO_GW_SRV_SET_ID:
827  trace("gateway: received 'Set node-ID' request");
828  return co_gw_recv_set_id(gw, net, req);
829 #ifndef LELY_NO_CO_EMCY
831  case CO_GW_SRV_EMCY_STOP:
832  trace("gateway: received '%s emergency consumer' request",
833  // clang-format off
834  req->srv == CO_GW_SRV_EMCY_START
835  ? "Start" : "Stop");
836  // clang-format on
837  return co_gw_recv_set_emcy(gw, net, node, req);
838 #endif
840  trace("gateway: received 'Set command time-out' request");
841  return co_gw_recv_set_cmd_timeout(gw, req);
843  trace("gateway: received 'Boot-up forwarding' request");
844  return co_gw_recv_set_bootup_ind(gw, net, req);
845  case CO_GW_SRV_SET_NET:
846  trace("gateway: received 'Set default network' request");
847  return co_gw_recv_set_net(gw, req);
848  case CO_GW_SRV_SET_NODE:
849  trace("gateway: received 'Set default node-ID' request");
850  return co_gw_recv_set_node(gw, net, req);
852  trace("gateway: received 'Get version' request");
853  return co_gw_recv_get_version(gw, net, req);
855  trace("gateway: received 'Set command size' request");
856  // We cannot guarantee a lack of memory resources will never
857  // occur.
858  return co_gw_send_con(gw, req, CO_GW_IEC_NO_MEM, 0);
859 #if !defined(LELY_NO_CO_MASTER) && !defined(LELY_NO_CO_LSS)
861  trace("gateway: received 'LSS switch state global' request");
862  return co_gw_recv_lss_switch(gw, net, req);
864  trace("gateway: received 'LSS switch state selective' request");
865  return co_gw_recv_lss_switch_sel(gw, net, req);
867  trace("gateway: received 'LSS configure node-ID' request");
868  return co_gw_recv_lss_set_id(gw, net, req);
870  trace("gateway: received 'LSS configure bit-rate' request");
871  return co_gw_recv_lss_set_rate(gw, net, req);
873  trace("gateway: received 'LSS activate new bit-rate' request");
874  return co_gw_recv_lss_switch_rate(gw, net, req);
875  case CO_GW_SRV_LSS_STORE:
876  trace("gateway: received 'LSS store configuration' request");
877  return co_gw_recv_lss_store(gw, net, req);
879  trace("gateway: received 'Inquire LSS address' request");
880  return co_gw_recv_lss_get_lssid(gw, net, req);
882  trace("gateway: received 'LSS inquire node-ID' request");
883  return co_gw_recv_lss_get_id(gw, net, req);
885  trace("gateway: received 'LSS identify remote slave' request");
886  return co_gw_recv_lss_id_slave(gw, net, req);
888  trace("gateway: received 'LSS identify non-configure remote slaves' request");
889  return co_gw_recv_lss_id_non_cfg_slave(gw, net, req);
891  trace("gateway: received 'LSS Slowscan' request");
892  return co_gw_recv__lss_slowscan(gw, net, req);
894  trace("gateway: received 'LSS Fastscan' request");
895  return co_gw_recv__lss_fastscan(gw, net, req);
896 #endif
897  default: iec = CO_GW_IEC_BAD_SRV; goto error;
898  }
899 
900 error:
901  return co_gw_send_con(gw, req, iec, 0);
902 }
903 
904 void
905 co_gw_get_send_func(const co_gw_t *gw, co_gw_send_func_t **pfunc, void **pdata)
906 {
907  assert(gw);
908 
909  if (pfunc)
910  *pfunc = gw->send_func;
911  if (pdata)
912  *pdata = gw->send_data;
913 }
914 
915 void
917 {
918  assert(gw);
919 
920  gw->send_func = func;
921  gw->send_data = data;
922 }
923 
924 void
925 co_gw_get_rate_func(const co_gw_t *gw, co_gw_rate_func_t **pfunc, void **pdata)
926 {
927  assert(gw);
928 
929  if (pfunc)
930  *pfunc = gw->rate_func;
931  if (pdata)
932  *pdata = gw->rate_data;
933 }
934 
935 void
937 {
938  assert(gw);
939 
940  gw->rate_func = func;
941  gw->rate_data = data;
942 }
943 
944 static struct co_gw_net *
945 co_gw_net_create(co_gw_t *gw, co_unsigned16_t id, co_nmt_t *nmt)
946 {
947  assert(gw);
948  assert(nmt);
949 
950  struct co_gw_net *net = malloc(sizeof(*net));
951  if (__unlikely(!net)) {
952  set_errc(errno2c(errno));
953  return NULL;
954  }
955 
956  net->gw = gw;
957  net->id = id;
958  net->nmt = nmt;
959 
960  net->def = 0;
961 #ifndef LELY_NO_CO_CSDO
962  net->timeout = 0;
963 #endif
964  net->bootup_ind = 1;
965 
966 #ifndef LELY_NO_CO_CSDO
967  for (co_unsigned8_t id = 1; id <= CO_NUM_NODES; id++)
968  net->sdo[id - 1] = NULL;
969 #endif
970 #if !defined(LELY_NO_CO_MASTER) && !defined(LELY_NO_CO_LSS)
971  net->lss = NULL;
972 #endif
973 
974  co_nmt_get_cs_ind(net->nmt, &net->cs_ind, &net->cs_data);
976 #ifndef LELY_NO_CO_MASTER
977  co_nmt_get_ng_ind(net->nmt, &net->ng_ind, &net->ng_data);
979 #endif
980  co_nmt_get_lg_ind(net->nmt, &net->lg_ind, &net->lg_data);
982  co_nmt_get_hb_ind(net->nmt, &net->hb_ind, &net->hb_data);
984  co_nmt_get_st_ind(net->nmt, &net->st_ind, &net->st_data);
986 #ifndef LELY_NO_CO_MASTER
987  co_nmt_get_boot_ind(net->nmt, &net->boot_ind, &net->boot_data);
989  co_nmt_get_dn_ind(net->nmt, &net->dn_ind, &net->dn_data);
991  co_nmt_get_dn_ind(net->nmt, &net->up_ind, &net->up_data);
993 #endif
994 
995 #ifndef LELY_NO_CO_SYNC
996  co_sync_t *sync = co_nmt_get_sync(nmt);
997  if (sync)
998  co_sync_set_ind(sync, &co_gw_net_sync_ind, net);
999 #endif
1000 
1001 #ifndef LELY_NO_CO_TIME
1002  co_time_t *time = co_nmt_get_time(nmt);
1003  if (time)
1004  co_time_set_ind(time, &co_gw_net_time_ind, net);
1005 #endif
1006 
1007 #ifndef LELY_NO_CO_EMCY
1008  co_emcy_t *emcy = co_nmt_get_emcy(nmt);
1009  if (emcy)
1010  co_emcy_set_ind(emcy, &co_gw_net_emcy_ind, net);
1011 #endif
1012 
1013 #ifndef LELY_NO_CO_RPDO
1014  if (co_nmt_get_st(net->nmt) == CO_NMT_ST_START) {
1015  for (co_unsigned16_t i = 1; i <= 512; i++) {
1016  co_rpdo_t *pdo = co_nmt_get_rpdo(nmt, i);
1017  if (pdo)
1018  co_rpdo_set_ind(pdo, &co_gw_net_rpdo_ind, net);
1019  }
1020  }
1021 #endif
1022 
1023  return net;
1024 }
1025 
1026 static void
1028 {
1029  if (net) {
1030 #ifndef LELY_NO_CO_RPDO
1031  for (co_unsigned16_t i = 1; i <= 512; i++) {
1032  co_rpdo_t *pdo = co_nmt_get_rpdo(net->nmt, i);
1033  if (pdo)
1034  co_rpdo_set_ind(pdo, NULL, NULL);
1035  }
1036 #endif
1037 
1038 #ifndef LELY_NO_CO_EMCY
1039  co_emcy_t *emcy = co_nmt_get_emcy(net->nmt);
1040  if (emcy)
1041  co_emcy_set_ind(emcy, NULL, NULL);
1042 #endif
1043 
1044 #ifndef LELY_NO_CO_TIME
1045  co_time_t *time = co_nmt_get_time(net->nmt);
1046  if (time)
1047  co_time_set_ind(time, NULL, NULL);
1048 #endif
1049 
1050 #ifndef LELY_NO_CO_SYNC
1051  co_sync_t *sync = co_nmt_get_sync(net->nmt);
1052  if (sync)
1053  co_sync_set_ind(sync, NULL, NULL);
1054 #endif
1055 
1056 #ifndef LELY_NO_CO_MASTER
1057  co_nmt_set_boot_ind(net->nmt, net->boot_ind, net->boot_data);
1058 #endif
1059  co_nmt_set_st_ind(net->nmt, net->st_ind, net->st_data);
1060  co_nmt_set_hb_ind(net->nmt, net->hb_ind, net->hb_data);
1061  co_nmt_set_lg_ind(net->nmt, net->lg_ind, net->lg_data);
1062 #ifndef LELY_NO_CO_MASTER
1063  co_nmt_set_ng_ind(net->nmt, net->ng_ind, net->ng_data);
1064 #endif
1065  co_nmt_set_cs_ind(net->nmt, net->cs_ind, net->cs_data);
1066 
1067 #ifndef LELY_NO_CO_CSDO
1068  for (co_unsigned8_t id = 1; id <= CO_NUM_NODES; id++)
1069  co_gw_job_destroy(net->sdo[id - 1]);
1070 #endif
1071 #if !defined(LELY_NO_CO_MASTER) && !defined(LELY_NO_CO_LSS)
1072  co_gw_job_destroy(net->lss);
1073 #endif
1074 
1075  free(net);
1076  }
1077 }
1078 
1079 static void
1080 co_gw_net_cs_ind(co_nmt_t *nmt, co_unsigned8_t cs, void *data)
1081 {
1082  struct co_gw_net *net = data;
1083  assert(net);
1084 
1085  switch (cs) {
1086  case CO_NMT_CS_START: {
1087 #ifndef LELY_NO_CO_SYNC
1088  co_sync_t *sync = co_nmt_get_sync(nmt);
1089  if (sync)
1090  co_sync_set_ind(sync, &co_gw_net_sync_ind, net);
1091 #endif
1092 
1093 #ifndef LELY_NO_CO_TIME
1094  co_time_t *time = co_nmt_get_time(nmt);
1095  if (time)
1096  co_time_set_ind(time, &co_gw_net_time_ind, net);
1097 #endif
1098 
1099 #ifndef LELY_NO_CO_EMCY
1100  co_emcy_t *emcy = co_nmt_get_emcy(nmt);
1101  if (emcy)
1102  co_emcy_set_ind(emcy, &co_gw_net_emcy_ind, net);
1103 #endif
1104 
1105 #ifndef LELY_NO_CO_RPDO
1106  for (co_unsigned16_t i = 1; i <= 512; i++) {
1107  co_rpdo_t *pdo = co_nmt_get_rpdo(nmt, i);
1108  if (pdo)
1109  co_rpdo_set_ind(pdo, &co_gw_net_rpdo_ind, net);
1110  }
1111 #endif
1112 
1113  break;
1114  }
1115  case CO_NMT_CS_ENTER_PREOP: {
1116 #ifndef LELY_NO_CO_SYNC
1117  co_sync_t *sync = co_nmt_get_sync(nmt);
1118  if (sync)
1119  co_sync_set_ind(sync, &co_gw_net_sync_ind, net);
1120 #endif
1121 
1122 #ifndef LELY_NO_CO_TIME
1123  co_time_t *time = co_nmt_get_time(nmt);
1124  if (time)
1125  co_time_set_ind(time, &co_gw_net_time_ind, net);
1126 #endif
1127 
1128 #ifndef LELY_NO_CO_EMCY
1129  co_emcy_t *emcy = co_nmt_get_emcy(nmt);
1130  if (emcy)
1131  co_emcy_set_ind(emcy, &co_gw_net_emcy_ind, net);
1132 #endif
1133 
1134  break;
1135  }
1136  }
1137 
1138  if (net->cs_ind)
1139  net->cs_ind(nmt, cs, net->cs_data);
1140 }
1141 
1142 #ifndef LELY_NO_CO_MASTER
1143 static void
1144 co_gw_net_ng_ind(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason,
1145  void *data)
1146 {
1147  struct co_gw_net *net = data;
1148  assert(net);
1149 
1150  if (state == CO_NMT_EC_OCCURRED) {
1151  int iec = 0;
1152  switch (state) {
1153  case CO_NMT_EC_TIMEOUT: iec = CO_GW_IEC_NG_OCCURRED; break;
1154  case CO_NMT_EC_STATE: iec = CO_GW_IEC_ST_OCCURRED; break;
1155  }
1156  co_gw_send_ec(net->gw, net->id, id, 0, iec);
1157  }
1158 
1159  if (net->ng_ind)
1160  net->ng_ind(nmt, id, state, reason, net->ng_data);
1161 }
1162 #endif
1163 
1164 static void
1165 co_gw_net_lg_ind(co_nmt_t *nmt, int state, void *data)
1166 {
1167  struct co_gw_net *net = data;
1168  assert(net);
1169 
1170  co_dev_t *dev = co_nmt_get_dev(nmt);
1171 
1172  co_unsigned8_t id = co_dev_get_id(dev);
1173  co_gw_send_ec(net->gw, net->id, id, 0, CO_GW_IEC_LG_OCCURRED);
1174 
1175  if (net->lg_ind)
1176  net->lg_ind(nmt, state, net->lg_data);
1177 }
1178 
1179 static void
1180 co_gw_net_hb_ind(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason,
1181  void *data)
1182 {
1183  struct co_gw_net *net = data;
1184  assert(net);
1185 
1186  if (reason == CO_NMT_EC_TIMEOUT) {
1187  int iec = 0;
1188  switch (state) {
1189  case CO_NMT_EC_OCCURRED: iec = CO_GW_IEC_HB_OCCURRED; break;
1190  case CO_NMT_EC_RESOLVED: iec = CO_GW_IEC_HB_RESOLVED; break;
1191  }
1192  co_gw_send_ec(net->gw, net->id, id, 0, iec);
1193  }
1194 
1195  if (net->hb_ind)
1196  net->hb_ind(nmt, id, state, reason, net->hb_data);
1197 }
1198 
1199 static void
1201  co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, void *data)
1202 {
1203  struct co_gw_net *net = data;
1204  assert(net);
1205 
1206  co_dev_t *dev = co_nmt_get_dev(nmt);
1207 
1208  // Ignore state change indications of the gateway itself.
1209  if (id == co_dev_get_id(dev))
1210  return;
1211 
1212  if (st == CO_NMT_ST_BOOTUP && !net->bootup_ind)
1213  return;
1214 
1215  co_gw_send_ec(net->gw, net->id, id, st,
1216  st == CO_NMT_ST_BOOTUP ? CO_GW_IEC_BOOTUP : 0);
1217 
1218  if (net->st_ind)
1219  net->st_ind(nmt, id, st, net->st_data);
1220 }
1221 
1222 #ifndef LELY_NO_CO_MASTER
1223 
1224 static void
1225 co_gw_net_boot_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, char es,
1226  void *data)
1227 {
1228  struct co_gw_net *net = data;
1229  assert(net);
1230 
1231  struct co_gw_ind__boot ind = { .size = sizeof(ind),
1232  .srv = CO_GW_SRV__BOOT,
1233  .net = net->id,
1234  .node = id,
1235  .st = st,
1236  .es = es };
1237  co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1238 
1239  if (net->boot_ind)
1240  net->boot_ind(nmt, id, st, es, net->boot_data);
1241 }
1242 
1243 static void
1244 co_gw_net_dn_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned16_t idx,
1245  co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
1246 {
1247  struct co_gw_net *net = data;
1248  assert(net);
1249 
1250  struct co_gw_ind_sdo ind = { .size = sizeof(ind),
1251  .srv = CO_GW_SRV_SDO,
1252  .net = net->id,
1253  .node = id,
1254  .nbyte = nbyte,
1255  .up = 0,
1256  .data = NULL,
1257  ._size = size };
1258  co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1259 
1260  if (net->dn_ind)
1261  net->dn_ind(nmt, id, idx, subidx, size, nbyte, net->dn_data);
1262 }
1263 
1264 static void
1265 co_gw_net_up_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned16_t idx,
1266  co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
1267 {
1268  struct co_gw_net *net = data;
1269  assert(net);
1270 
1271  struct co_gw_ind_sdo ind = { .size = sizeof(ind),
1272  .srv = CO_GW_SRV_SDO,
1273  .net = net->id,
1274  .node = id,
1275  .nbyte = nbyte,
1276  .up = 1,
1277  .data = NULL,
1278  ._size = size };
1279  co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1280 
1281  if (net->up_ind)
1282  net->up_ind(nmt, id, idx, subidx, size, nbyte, net->up_data);
1283 }
1284 
1285 #endif // !LELY_NO_CO_MASTER
1286 
1287 #ifndef LELY_NO_CO_SYNC
1288 static void
1289 co_gw_net_sync_ind(co_sync_t *sync, co_unsigned8_t cnt, void *data)
1290 {
1291  (void)sync;
1292  struct co_gw_net *net = data;
1293  assert(net);
1294 
1295  struct co_gw_ind__sync ind = { .size = sizeof(ind),
1296  .srv = CO_GW_SRV__SYNC,
1297  .net = net->id,
1298  .cnt = cnt };
1299  co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1300 
1301  co_nmt_on_sync(net->nmt, cnt);
1302 }
1303 #endif
1304 
1305 #ifndef LELY_NO_CO_TIME
1306 static void
1307 co_gw_net_time_ind(co_time_t *time, const struct timespec *tp, void *data)
1308 {
1309  (void)time;
1310  struct co_gw_net *net = data;
1311  assert(net);
1312 
1313  struct co_gw_ind__time ind = { .size = sizeof(ind),
1314  .srv = CO_GW_SRV__TIME,
1315  .net = net->id,
1316  .ts = *tp };
1317  co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1318 }
1319 #endif
1320 
1321 #ifndef LELY_NO_CO_EMCY
1322 static void
1323 co_gw_net_emcy_ind(co_emcy_t *emcy, co_unsigned8_t id, co_unsigned16_t ec,
1324  co_unsigned8_t er, uint8_t msef[5], void *data)
1325 {
1326  (void)emcy;
1327  struct co_gw_net *net = data;
1328  assert(net);
1329 
1330  struct co_gw_ind_emcy ind = { .size = sizeof(ind),
1331  .srv = CO_GW_SRV_EMCY,
1332  .net = net->id,
1333  .node = id,
1334  .ec = ec,
1335  .er = er,
1336  .msef = { msef[0], msef[1], msef[2], msef[3], msef[4] } };
1337  co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1338 }
1339 #endif
1340 
1341 static struct co_gw_job *
1343  void (*dtor)(void *data), const struct co_gw_req *req)
1344 {
1345  assert(pself);
1346  assert(req);
1347 
1348  if (*pself)
1350 
1351  *pself = malloc(CO_GW_JOB_SIZE + req->size);
1352  if (__unlikely(!*pself)) {
1353  set_errc(errno2c(errno));
1354  return NULL;
1355  }
1356 
1357  (*pself)->pself = pself;
1358  (*pself)->net = net;
1359  (*pself)->data = data;
1360  (*pself)->dtor = dtor;
1361  memcpy(&(*pself)->req, req, req->size);
1362 
1363  return *pself;
1364 }
1365 
1366 static void
1368 {
1369  (void)co_gw_job_create;
1370 
1371  if (job) {
1372  co_gw_job_remove(job);
1373 
1374  if (job->dtor)
1375  job->dtor(job->data);
1376 
1377  free(job);
1378  }
1379 }
1380 
1381 static void
1383 {
1384  assert(job);
1385 
1386  if (job->pself && *job->pself == job)
1387  *job->pself = NULL;
1388 }
1389 
1390 #ifndef LELY_NO_CO_CSDO
1391 
1392 static struct co_gw_job *
1394  co_unsigned8_t id, const struct co_gw_req *req)
1395 {
1396  assert(pself);
1397  assert(net);
1398 
1399  co_gw_t *gw = net->gw;
1400 
1401  int errc = 0;
1402 
1403  if (__unlikely(*pself)) {
1404  errc = errnum2c(ERRNUM_BUSY);
1405  goto error_param;
1406  }
1407 
1408  co_csdo_t *sdo = co_csdo_create(co_nmt_get_net(net->nmt), NULL, id);
1409  if (__unlikely(!sdo)) {
1410  errc = get_errc();
1411  goto error_create_sdo;
1412  }
1413 
1414  // The actual SDO timeout is limited by the global gateway command
1415  // timeout.
1416  int timeout = net->timeout;
1417  if (gw->timeout)
1418  timeout = timeout ? MIN(timeout, gw->timeout) : gw->timeout;
1419  co_csdo_set_timeout(sdo, timeout);
1420 
1421  struct co_gw_job *job = co_gw_job_create(
1422  pself, net, sdo, &co_gw_job_sdo_dtor, req);
1423  if (__unlikely(!job)) {
1424  errc = get_errc();
1425  goto error_create_job;
1426  }
1427 
1428  return job;
1429 
1430 error_create_job:
1431  co_csdo_destroy(sdo);
1432 error_create_sdo:
1433 error_param:
1434  set_errc(errc);
1435  return NULL;
1436 }
1437 
1438 static void
1440 {
1441  co_csdo_t *sdo = data;
1442 
1443  co_csdo_destroy(sdo);
1444 }
1445 
1446 static void
1447 co_gw_job_sdo_up_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1448  co_unsigned32_t ac, const void *ptr, size_t n, void *data)
1449 {
1450  (void)sdo;
1451  (void)idx;
1452  (void)subidx;
1453  struct co_gw_job *job = data;
1454  assert(job);
1455  assert(job->net);
1456 
1457  co_gw_job_remove(job);
1458 
1459  if (__unlikely(job->req.srv != CO_GW_SRV_SDO_UP))
1460  goto done;
1461  struct co_gw_req_sdo_up *req = (struct co_gw_req_sdo_up *)&job->req;
1462 
1463  if (ac) {
1464  co_gw_send_con(job->net->gw, &job->req, 0, ac);
1465  } else {
1466  size_t size = MAX(CO_GW_CON_SDO_UP_SIZE + n,
1467  sizeof(struct co_gw_con_sdo_up));
1468  int errc = get_errc();
1469  struct co_gw_con_sdo_up *con = malloc(size);
1470  if (__likely(con)) {
1471  *con = (struct co_gw_con_sdo_up){ .size = size,
1472  .srv = req->srv,
1473  .data = req->data,
1474  .type = req->type,
1475  .len = n };
1476  memcpy(con->val, ptr, n);
1477  co_gw_send_srv(job->net->gw, (struct co_gw_srv *)con);
1478 
1479  free(con);
1480  } else {
1481  set_errc(errc);
1482  co_gw_send_con(job->net->gw, &job->req,
1483  CO_GW_IEC_NO_MEM, 0);
1484  }
1485  }
1486 
1487 done:
1488  co_gw_job_destroy(job);
1489 }
1490 
1491 static void
1492 co_gw_job_sdo_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1493  co_unsigned32_t ac, void *data)
1494 {
1495  (void)sdo;
1496  (void)idx;
1497  (void)subidx;
1498  struct co_gw_job *job = data;
1499  assert(job);
1500  assert(job->net);
1501 
1502  co_gw_job_remove(job);
1503 
1504  if (__likely(job->req.srv == CO_GW_SRV_SDO_DN))
1505  co_gw_send_con(job->net->gw, &job->req, 0, ac);
1506 
1507  co_gw_job_destroy(job);
1508 }
1509 
1510 static void
1511 co_gw_job_sdo_ind(const co_csdo_t *sdo, co_unsigned16_t idx,
1512  co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
1513 {
1514  (void)sdo;
1515  (void)idx;
1516  (void)subidx;
1517  struct co_gw_job *job = data;
1518  assert(job);
1519  assert(job->net);
1520 
1521  struct co_gw_ind_sdo ind = { .size = sizeof(ind),
1522  .srv = CO_GW_SRV_SDO,
1523  .net = job->net->id,
1524  .node = co_csdo_get_num(job->data),
1525  .nbyte = nbyte,
1526  .up = job->req.srv == CO_GW_SRV_SDO_UP,
1527  .data = job->req.data,
1528  ._size = size };
1529  co_gw_send_srv(job->net->gw, (struct co_gw_srv *)&ind);
1530 }
1531 
1532 #endif // !LELY_NO_CO_CSDO
1533 
1534 #if !defined(LELY_NO_CO_MASTER) && !defined(LELY_NO_CO_LSS)
1535 
1536 static struct co_gw_job *
1538  const struct co_gw_req *req)
1539 {
1540  assert(pself);
1541  assert(net);
1542 
1543  co_gw_t *gw = net->gw;
1544 
1545  if (__unlikely(*pself)) {
1547  return NULL;
1548  }
1549 
1550  co_lss_t *lss = co_nmt_get_lss(net->nmt);
1551  if (__unlikely(!lss)) {
1553  return NULL;
1554  }
1555 
1556  // The LSS timeout is limited by the global gateway command timeout.
1557  int timeout = LELY_CO_LSS_TIMEOUT;
1558  if (gw->timeout)
1559  timeout = MIN(timeout, gw->timeout);
1560  co_lss_set_timeout(lss, timeout);
1561 
1562  return co_gw_job_create(pself, net, lss, NULL, req);
1563 }
1564 
1565 static void
1566 co_gw_job_lss_cs_ind(co_lss_t *lss, co_unsigned8_t cs, void *data)
1567 {
1568  (void)lss;
1569  struct co_gw_job *job = data;
1570  assert(job);
1571  assert(job->net);
1572 
1573  co_gw_job_remove(job);
1574 
1575  int iec = CO_GW_IEC_TIMEOUT;
1576  if (cs) {
1577  iec = CO_GW_IEC_LSS;
1578  switch (job->req.srv) {
1580  if (cs == 0x44)
1581  iec = 0;
1582  break;
1584  if (cs == 0x4f)
1585  iec = 0;
1586  break;
1588  if (cs == 0x50)
1589  iec = 0;
1590  break;
1591  }
1592  }
1593  co_gw_send_con(job->net->gw, &job->req, iec, 0);
1594 
1595  co_gw_job_destroy(job);
1596 }
1597 
1598 static void
1599 co_gw_job_lss_err_ind(co_lss_t *lss, co_unsigned8_t cs, co_unsigned8_t err,
1600  co_unsigned8_t spec, void *data)
1601 {
1602  (void)lss;
1603  (void)spec;
1604  struct co_gw_job *job = data;
1605  assert(job);
1606  assert(job->net);
1607 
1608  co_gw_job_remove(job);
1609 
1610  int iec = CO_GW_IEC_TIMEOUT;
1611  if (cs) {
1612  iec = CO_GW_IEC_LSS;
1613  switch (job->req.srv) {
1614  case CO_GW_SRV_LSS_SET_ID:
1615  if (cs == 0x11)
1616  iec = err ? CO_GW_IEC_LSS_ID : 0;
1617  break;
1619  if (cs == 0x13)
1620  iec = err ? CO_GW_IEC_LSS_RATE : 0;
1621  break;
1622  case CO_GW_SRV_LSS_STORE:
1623  if (cs == 0x17)
1624  iec = err ? CO_GW_IEC_LSS_PARAM : 0;
1625  break;
1626  }
1627  }
1628  co_gw_send_con(job->net->gw, &job->req, iec, 0);
1629 
1630  co_gw_job_destroy(job);
1631 }
1632 
1633 static void
1634 co_gw_job_lss_lssid_ind(co_lss_t *lss, co_unsigned8_t cs, co_unsigned32_t id,
1635  void *data)
1636 {
1637  (void)lss;
1638  struct co_gw_job *job = data;
1639  assert(job);
1640  assert(job->net);
1641  assert(job->req.srv == CO_GW_SRV_LSS_GET_LSSID);
1642  assert(job->req.size >= sizeof(struct co_gw_req_lss_get_lssid));
1643 
1644  struct co_gw_req_lss_get_lssid *req =
1645  (struct co_gw_req_lss_get_lssid *)&job->req;
1646 
1647  co_gw_job_remove(job);
1648 
1649  int iec = 0;
1650  if (!cs)
1651  iec = CO_GW_IEC_TIMEOUT;
1652  else if (cs != req->cs)
1653  iec = CO_GW_IEC_LSS;
1654 
1655  if (iec) {
1656  co_gw_send_con(job->net->gw, &job->req, iec, 0);
1657  } else {
1658  struct co_gw_con_lss_get_lssid con = { .size = sizeof(con),
1659  .srv = req->srv,
1660  .data = req->data,
1661  .id = id };
1662  co_gw_send_srv(job->net->gw, (struct co_gw_srv *)&con);
1663  }
1664 
1665  co_gw_job_destroy(job);
1666 }
1667 
1668 static void
1670  co_lss_t *lss, co_unsigned8_t cs, co_unsigned8_t id, void *data)
1671 {
1672  (void)lss;
1673  struct co_gw_job *job = data;
1674  assert(job);
1675  assert(job->net);
1676  assert(job->req.srv == CO_GW_SRV_LSS_GET_ID);
1677 
1678  co_gw_job_remove(job);
1679 
1680  int iec = 0;
1681  if (!cs)
1682  iec = CO_GW_IEC_TIMEOUT;
1683  else if (cs != 0x5e)
1684  iec = CO_GW_IEC_LSS;
1685 
1686  if (iec) {
1687  co_gw_send_con(job->net->gw, &job->req, iec, 0);
1688  } else {
1689  struct co_gw_con_lss_get_id con = { .size = sizeof(con),
1690  .srv = job->req.srv,
1691  .data = job->req.data,
1692  .id = id };
1693  co_gw_send_srv(job->net->gw, (struct co_gw_srv *)&con);
1694  }
1695 
1696  co_gw_job_destroy(job);
1697 }
1698 
1699 static void
1700 co_gw_job_lss_scan_ind(co_lss_t *lss, co_unsigned8_t cs, const struct co_id *id,
1701  void *data)
1702 {
1703  (void)lss;
1704  struct co_gw_job *job = data;
1705  assert(job);
1706  assert(job->net);
1707 
1708  co_gw_job_remove(job);
1709 
1710  int iec = CO_GW_IEC_TIMEOUT;
1711  if (cs) {
1712  iec = CO_GW_IEC_LSS;
1713  switch (job->req.srv) {
1715  if (cs == 0x44)
1716  iec = 0;
1717  break;
1719  if (cs == 0x4f)
1720  iec = 0;
1721  break;
1722  }
1723  }
1724 
1725  if (iec) {
1726  co_gw_send_con(job->net->gw, &job->req, iec, 0);
1727  } else {
1728  assert(id);
1729  struct co_gw_con__lss_scan con = { .size = sizeof(con),
1730  .srv = job->req.srv,
1731  .data = job->req.data,
1732  .id = *id };
1733  co_gw_send_srv(job->net->gw, (struct co_gw_srv *)&con);
1734  }
1735 
1736  co_gw_job_destroy(job);
1737 }
1738 
1739 #endif // !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
1740 
1741 #ifndef LELY_NO_CO_RPDO
1742 static void
1743 co_gw_net_rpdo_ind(co_rpdo_t *pdo, co_unsigned32_t ac, const void *ptr,
1744  size_t n, void *data)
1745 {
1746  struct co_gw_net *net = data;
1747  assert(net);
1748 
1749  if (__unlikely(ac))
1750  return;
1751 
1752  struct co_gw_ind_rpdo ind = { .size = CO_GW_IND_RPDO_SIZE,
1753  .srv = CO_GW_SRV_RPDO,
1754  .net = net->id,
1755  .num = co_rpdo_get_num(pdo),
1756  .n = 0x40 };
1757 
1758  const struct co_pdo_map_par *par = co_rpdo_get_map_par(pdo);
1759  if (__unlikely(co_pdo_unmap(par, ptr, n, ind.val, &ind.n)))
1760  return;
1761  ind.size += ind.n * sizeof(*ind.val);
1762 
1763  co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1764 }
1765 #endif
1766 
1767 #ifndef LELY_NO_CO_CSDO
1768 
1769 static int
1770 co_gw_recv_sdo_up(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
1771  const struct co_gw_req *req)
1772 {
1773  assert(gw);
1774  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
1775  assert(req);
1776  assert(req->srv == CO_GW_SRV_SDO_UP);
1777  assert(node && node <= CO_NUM_NODES);
1778 
1779  co_nmt_t *nmt = gw->net[net - 1]->nmt;
1780  co_dev_t *dev = co_nmt_get_dev(nmt);
1781 
1782  if (__unlikely(req->size < sizeof(struct co_gw_req_sdo_up))) {
1784  return -1;
1785  }
1786  const struct co_gw_req_sdo_up *par =
1787  (const struct co_gw_req_sdo_up *)req;
1788 
1789  int iec = 0;
1790  int errc = get_errc();
1791 
1792  struct co_gw_job *job = NULL;
1793  if (node == co_dev_get_id(dev)) {
1794  job = co_gw_job_create(&gw->net[net - 1]->sdo[node - 1],
1795  gw->net[net - 1], NULL, NULL, req);
1796  if (__unlikely(!job)) {
1797  iec = errnum2iec(get_errnum());
1798  goto error_create_job;
1799  }
1800 
1801  // clang-format off
1802  if (__unlikely(co_dev_up_req(dev, par->idx, par->subidx,
1803  &co_gw_job_sdo_up_con, job) == -1)) {
1804  // clang-format on
1805  iec = errnum2iec(get_errnum());
1806  goto error_up_req;
1807  }
1808  } else {
1809  if (!co_nmt_is_master(gw->net[net - 1]->nmt)) {
1810  // TODO: Add client-SDO support for slaves where
1811  // possible.
1812  iec = CO_GW_IEC_BAD_NODE;
1813  goto error_srv;
1814  }
1815 
1816  job = co_gw_job_create_sdo(&gw->net[net - 1]->sdo[node - 1],
1817  gw->net[net - 1], node, req);
1818  if (__unlikely(!job)) {
1819  iec = errnum2iec(get_errnum());
1820  goto error_create_job;
1821  }
1822 
1824  // clang-format off
1825  if (__unlikely(co_csdo_up_req(job->data, par->idx, par->subidx,
1826  &co_gw_job_sdo_up_con, job) == -1)) {
1827  // clang-format on
1828  iec = errnum2iec(get_errnum());
1829  goto error_up_req;
1830  }
1831  }
1832 
1833  return 0;
1834 
1835 error_up_req:
1836  co_gw_job_destroy(job);
1837 error_create_job:
1838  set_errc(errc);
1839 error_srv:
1840  return co_gw_send_con(gw, req, iec, 0);
1841 }
1842 
1843 static int
1844 co_gw_recv_sdo_dn(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
1845  const struct co_gw_req *req)
1846 {
1847  assert(gw);
1848  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
1849  assert(req);
1850  assert(req->srv == CO_GW_SRV_SDO_DN);
1851 
1852  co_nmt_t *nmt = gw->net[net - 1]->nmt;
1853  co_dev_t *dev = co_nmt_get_dev(nmt);
1854 
1857  return -1;
1858  }
1859  const struct co_gw_req_sdo_dn *par =
1860  (const struct co_gw_req_sdo_dn *)req;
1861  if (__unlikely(par->size < CO_GW_REQ_SDO_DN_SIZE + par->len)) {
1863  return -1;
1864  }
1865 
1866  int iec = 0;
1867  int errc = get_errc();
1868 
1869  struct co_gw_job *job = NULL;
1870  if (node == co_dev_get_id(dev)) {
1871  job = co_gw_job_create(&gw->net[net - 1]->sdo[node - 1],
1872  gw->net[net - 1], NULL, NULL, req);
1873  if (__unlikely(!job)) {
1874  iec = errnum2iec(get_errnum());
1875  goto error_create_job;
1876  }
1877 
1878  // clang-format off
1879  if (__unlikely(co_dev_dn_req(dev, par->idx, par->subidx,
1880  par->val, par->len, &co_gw_job_sdo_dn_con, job)
1881  == -1)) {
1882  // clang-format on
1883  iec = errnum2iec(get_errnum());
1884  goto error_dn_req;
1885  }
1886  } else {
1887  if (!co_nmt_is_master(gw->net[net - 1]->nmt)) {
1888  // TODO: Add client-SDO support for slaves where
1889  // possible.
1890  iec = CO_GW_IEC_BAD_NODE;
1891  goto error_srv;
1892  }
1893 
1894  job = co_gw_job_create_sdo(&gw->net[net - 1]->sdo[node - 1],
1895  gw->net[net - 1], node, req);
1896  if (__unlikely(!job)) {
1897  iec = errnum2iec(get_errnum());
1898  goto error_create_job;
1899  }
1900 
1902  // clang-format off
1903  if (__unlikely(co_csdo_dn_req(job->data, par->idx, par->subidx,
1904  par->val, par->len, &co_gw_job_sdo_dn_con, job)
1905  == -1)) {
1906  // clang-format on
1907  iec = errnum2iec(get_errnum());
1908  goto error_dn_req;
1909  }
1910  }
1911 
1912  return 0;
1913 
1914 error_dn_req:
1915  co_gw_job_destroy(job);
1916 error_create_job:
1917  set_errc(errc);
1918 error_srv:
1919  return co_gw_send_con(gw, req, iec, 0);
1920 }
1921 
1922 static int
1924  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
1925 {
1926  assert(gw);
1927  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
1928  assert(req);
1929  assert(req->srv == CO_GW_SRV_SET_SDO_TIMEOUT);
1930 
1931 #ifndef LELY_NO_CO_MASTER
1932  co_nmt_t *nmt = gw->net[net - 1]->nmt;
1933 #endif
1934 
1935  if (__unlikely(req->size < sizeof(struct co_gw_req_set_sdo_timeout))) {
1937  return -1;
1938  }
1939  const struct co_gw_req_set_sdo_timeout *par =
1940  (const struct co_gw_req_set_sdo_timeout *)req;
1941 
1942  gw->net[net - 1]->timeout = par->timeout;
1943 
1944 #ifndef LELY_NO_CO_MASTER
1945  // The actual NMT SDO timeout is limited by the global gateway command
1946  // timeout.
1947  int timeout = par->timeout;
1948  if (gw->timeout)
1949  timeout = timeout ? MIN(timeout, gw->timeout) : gw->timeout;
1951 #endif
1952 
1953  return co_gw_send_con(gw, req, 0, 0);
1954 }
1955 
1956 #endif
1957 
1958 #ifndef LELY_NO_CO_RPDO
1959 static int
1961  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
1962 {
1963  assert(gw);
1964  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
1965  assert(req);
1966  assert(req->srv == CO_GW_SRV_SET_RPDO);
1967 
1968  co_nmt_t *nmt = gw->net[net - 1]->nmt;
1969  co_dev_t *dev = co_nmt_get_dev(nmt);
1970 
1971  if (__unlikely(req->size < CO_GW_REQ_SET_RPDO_SIZE)) {
1973  return -1;
1974  }
1975  const struct co_gw_req_set_rpdo *par =
1976  (const struct co_gw_req_set_rpdo *)req;
1977  // clang-format off
1978  if (__unlikely(par->n > 0x40 || par->size < CO_GW_REQ_SET_RPDO_SIZE
1979  + par->n * sizeof(*par->map))) {
1980  // clang-format on
1982  return -1;
1983  }
1984 
1985  struct co_pdo_comm_par comm = {
1986  .n = 2, .cobid = par->cobid, .trans = par->trans
1987  };
1988 
1990  map.n = par->n;
1991  for (co_unsigned8_t i = 0; i < par->n; i++)
1992  map.map[i] = par->map[i];
1993 
1994  co_unsigned32_t ac = co_dev_cfg_rpdo(dev, par->num, &comm, &map);
1995 
1996  return co_gw_send_con(gw, req, 0, ac);
1997 }
1998 #endif
1999 
2000 #ifndef LELY_NO_CO_TPDO
2001 static int
2003  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2004 {
2005  assert(gw);
2006  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2007  assert(req);
2008  assert(req->srv == CO_GW_SRV_SET_TPDO);
2009 
2010  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2011  co_dev_t *dev = co_nmt_get_dev(nmt);
2012 
2013  if (__unlikely(req->size < CO_GW_REQ_SET_TPDO_SIZE)) {
2015  return -1;
2016  }
2017  const struct co_gw_req_set_tpdo *par =
2018  (const struct co_gw_req_set_tpdo *)req;
2019  // clang-format off
2020  if (__unlikely(par->n > 0x40 || par->size < CO_GW_REQ_SET_TPDO_SIZE
2021  + par->n * sizeof(*par->map))) {
2022  // clang-format on
2024  return -1;
2025  }
2026 
2027  struct co_pdo_comm_par comm = { .n = 6,
2028  .cobid = par->cobid,
2029  .trans = par->trans,
2030  .inhibit = par->inhibit,
2031  .event = par->event,
2032  .sync = par->sync };
2033 
2035  map.n = par->n;
2036  for (co_unsigned8_t i = 0; i < par->n; i++)
2037  map.map[i] = par->map[i];
2038 
2039  co_unsigned32_t ac = co_dev_cfg_tpdo(dev, par->num, &comm, &map);
2040 
2041  return co_gw_send_con(gw, req, 0, ac);
2042 }
2043 #endif
2044 
2045 #ifndef LELY_NO_CO_RPDO
2046 static int
2048  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2049 {
2050  assert(gw);
2051  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2052  assert(req);
2053  assert(req->srv == CO_GW_SRV_PDO_READ);
2054 
2055  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2056  co_dev_t *dev = co_nmt_get_dev(nmt);
2057 
2058  if (__unlikely(req->size < sizeof(struct co_gw_req_pdo_read))) {
2060  return -1;
2061  }
2062  const struct co_gw_req_pdo_read *par =
2063  (const struct co_gw_req_pdo_read *)req;
2064 
2065  int iec = 0;
2066  co_unsigned32_t ac = 0;
2067 
2068  co_rpdo_t *pdo = co_nmt_get_rpdo(nmt, par->num);
2069  if (__unlikely(!pdo)) {
2070  iec = CO_GW_IEC_INTERN;
2071  goto error;
2072  }
2073  const struct co_pdo_comm_par *comm = co_rpdo_get_comm_par(pdo);
2074  if (comm->trans == 0xfc || comm->trans == 0xfd) {
2075  // TODO(jseldenthuis@lely.com): Send an RTR and wait for the
2076  // result.
2077  iec = CO_GW_IEC_INTERN;
2078  goto error;
2079  }
2080  const struct co_pdo_map_par *map = co_rpdo_get_map_par(pdo);
2081 
2082  // Read the mapped values from the object dictionary.
2083  struct co_sdo_req sdo_req = CO_SDO_REQ_INIT;
2084  uint8_t buf[CAN_MAX_LEN];
2085  size_t n = sizeof(buf);
2086  ac = co_pdo_up(map, dev, &sdo_req, buf, &n);
2087  co_sdo_req_fini(&sdo_req);
2088  if (__unlikely(ac))
2089  goto error;
2090 
2091  struct co_gw_con_pdo_read con = { .size = sizeof(con),
2092  .srv = req->srv,
2093  .data = req->data,
2094  .net = net,
2095  .num = par->num };
2096 
2097  // Unmap the PDO values.
2098  ac = co_pdo_unmap(map, buf, n, con.val, &con.n);
2099  if (__unlikely(ac))
2100  goto error;
2101 
2102  con.size += con.n * sizeof(*con.val);
2103  return co_gw_send_srv(gw, (struct co_gw_srv *)&con);
2104 
2105 error:
2106  return co_gw_send_con(gw, req, iec, ac);
2107 }
2108 #endif
2109 
2110 #ifndef LELY_NO_CO_TPDO
2111 static int
2113  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2114 {
2115  assert(gw);
2116  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2117  assert(req);
2118  assert(req->srv == CO_GW_SRV_PDO_WRITE);
2119 
2120  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2121  co_dev_t *dev = co_nmt_get_dev(nmt);
2122 
2125  return -1;
2126  }
2127  const struct co_gw_req_pdo_write *par =
2128  (const struct co_gw_req_pdo_write *)req;
2129  // clang-format off
2130  if (__unlikely(par->n > 0x40 || par->size < CO_GW_REQ_PDO_WRITE_SIZE
2131  + par->n * sizeof(*par->val))) {
2132  // clang-format on
2134  return -1;
2135  }
2136 
2137  int iec = 0;
2138  co_unsigned32_t ac = 0;
2139 
2140  co_tpdo_t *pdo = co_nmt_get_tpdo(nmt, par->num);
2141  if (__unlikely(!pdo)) {
2142  iec = CO_GW_IEC_INTERN;
2143  goto error;
2144  }
2145  const struct co_pdo_map_par *map = co_tpdo_get_map_par(pdo);
2146 
2147  // Map the values into a PDO.
2148  uint8_t buf[CAN_MAX_LEN] = { 0 };
2149  size_t n = sizeof(buf);
2150  ac = co_pdo_map(map, par->val, par->n, buf, &n);
2151  if (__unlikely(ac))
2152  goto error;
2153 
2154  // Write the mapped values to the object dictionary.
2155  struct co_sdo_req sdo_req = CO_SDO_REQ_INIT;
2156  ac = co_pdo_dn(map, dev, &sdo_req, buf, n);
2157  co_sdo_req_fini(&sdo_req);
2158  if (__unlikely(ac))
2159  goto error;
2160 
2161  // Trigger the event-based TPDO, if necessary.
2162  int errc = 0;
2163  if (__unlikely(co_tpdo_event(pdo) == -1)) {
2164  iec = errnum2iec(get_errnum());
2165  set_errc(errc);
2166  }
2167 
2168 error:
2169  return co_gw_send_con(gw, req, iec, ac);
2170 }
2171 #endif
2172 
2173 #ifndef LELY_NO_CO_MASTER
2174 
2175 static int
2176 co_gw_recv_nmt_cs(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
2177  co_unsigned8_t cs, const struct co_gw_req *req)
2178 {
2179  assert(gw);
2180  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2181  assert(req);
2182 
2183  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2184 
2185  int iec = 0;
2186 
2187  int errc = get_errc();
2188  if (__unlikely(co_nmt_cs_req(nmt, cs, node) == -1)) {
2189  iec = errnum2iec(get_errnum());
2190  set_errc(errc);
2191  }
2192 
2193  return co_gw_send_con(gw, req, iec, 0);
2194 }
2195 
2196 static int
2197 co_gw_recv_nmt_set_ng(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
2198  const struct co_gw_req *req)
2199 {
2200  assert(gw);
2201  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2202  assert(req);
2203 
2204  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2205 
2206  co_unsigned16_t gt = 0;
2207  co_unsigned8_t ltf = 0;
2208  if (req->srv == CO_GW_SRV_NMT_NG_ENABLE) {
2209  // clang-format off
2210  if (__unlikely(req->size
2211  < sizeof(struct co_gw_req_nmt_set_ng))) {
2212  // clang-format on
2214  return -1;
2215  }
2216  const struct co_gw_req_nmt_set_ng *par =
2217  (const struct co_gw_req_nmt_set_ng *)req;
2218 
2219  gt = par->gt;
2220  ltf = par->ltf;
2221  }
2222 
2223  int iec = 0;
2224 
2225  int errc = get_errc();
2226  if (__unlikely(co_nmt_ng_req(nmt, node, gt, ltf) == -1)) {
2227  iec = errnum2iec(get_errnum());
2228  set_errc(errc);
2229  }
2230 
2231  return co_gw_send_con(gw, req, iec, 0);
2232 }
2233 
2234 #endif // !LELY_NO_CO_MASTER
2235 
2236 static int
2237 co_gw_recv_nmt_set_hb(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
2238  const struct co_gw_req *req)
2239 {
2240  assert(gw);
2241  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2242  assert(req);
2243 
2244  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2245  co_dev_t *dev = co_nmt_get_dev(nmt);
2246 
2247  co_unsigned16_t ms = 0;
2248  if (req->srv == CO_GW_SRV_NMT_HB_ENABLE) {
2249  // clang-format off
2250  if (__unlikely(req->size
2251  < sizeof(struct co_gw_req_nmt_set_hb))) {
2252  // clang-format on
2254  return -1;
2255  }
2256  const struct co_gw_req_nmt_set_hb *par =
2257  (const struct co_gw_req_nmt_set_hb *)req;
2258 
2259  ms = par->ms;
2260  }
2261 
2262  co_unsigned32_t ac = co_dev_cfg_hb(dev, node, ms);
2263 
2264  return co_gw_send_con(gw, req, 0, ac);
2265 }
2266 
2267 static int
2268 co_gw_recv_init(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2269 {
2270  assert(gw);
2271  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2272  assert(req);
2273  assert(req->srv == CO_GW_SRV_INIT);
2274 
2275  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2276  co_dev_t *dev = co_nmt_get_dev(nmt);
2277 
2278  if (__unlikely(req->size < sizeof(struct co_gw_req_init))) {
2280  return -1;
2281  }
2282  const struct co_gw_req_init *par = (const struct co_gw_req_init *)req;
2283 
2284  int iec = 0;
2285 
2286  unsigned int baud = co_dev_get_baud(dev);
2287  co_unsigned16_t rate;
2288  switch (par->bitidx) {
2289  case 0:
2290  if (__unlikely(!(baud & CO_BAUD_1000))) {
2291  iec = CO_GW_IEC_LSS_RATE;
2292  goto error;
2293  }
2294  rate = 1000;
2295  break;
2296  case 1:
2297  if (__unlikely(!(baud & CO_BAUD_800))) {
2298  iec = CO_GW_IEC_LSS_RATE;
2299  goto error;
2300  }
2301  rate = 800;
2302  break;
2303  case 2:
2304  if (__unlikely(!(baud & CO_BAUD_500))) {
2305  iec = CO_GW_IEC_LSS_RATE;
2306  goto error;
2307  }
2308  rate = 500;
2309  break;
2310  case 3:
2311  if (__unlikely(!(baud & CO_BAUD_250))) {
2312  iec = CO_GW_IEC_LSS_RATE;
2313  goto error;
2314  }
2315  rate = 250;
2316  break;
2317  case 4:
2318  if (__unlikely(!(baud & CO_BAUD_125))) {
2319  iec = CO_GW_IEC_LSS_RATE;
2320  goto error;
2321  }
2322  rate = 125;
2323  break;
2324  case 6:
2325  if (__unlikely(!(baud & CO_BAUD_50))) {
2326  iec = CO_GW_IEC_LSS_RATE;
2327  goto error;
2328  }
2329  rate = 50;
2330  break;
2331  case 7:
2332  if (__unlikely(!(baud & CO_BAUD_20))) {
2333  iec = CO_GW_IEC_LSS_RATE;
2334  goto error;
2335  }
2336  rate = 20;
2337  break;
2338  case 8:
2339  if (__unlikely(!(baud & CO_BAUD_10))) {
2340  iec = CO_GW_IEC_LSS_RATE;
2341  goto error;
2342  }
2343  rate = 10;
2344  break;
2345  case 9:
2346  if (__unlikely(!(baud & CO_BAUD_AUTO))) {
2347  iec = CO_GW_IEC_LSS_RATE;
2348  goto error;
2349  }
2350  rate = 0;
2351  break;
2352  default: iec = CO_GW_IEC_LSS_RATE; goto error;
2353  }
2354  if (gw->rate_func)
2355  gw->rate_func(net, rate, gw->rate_data);
2356 
2357  int errc = get_errc();
2358  if (__unlikely(co_nmt_cs_ind(nmt, CO_NMT_CS_RESET_NODE) == -1)) {
2359  iec = errnum2iec(get_errnum());
2360  set_errc(errc);
2361  }
2362 
2363 error:
2364  return co_gw_send_con(gw, req, iec, 0);
2365 }
2366 
2367 static int
2368 co_gw_recv_set_hb(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2369 {
2370  assert(gw);
2371  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2372  assert(req);
2373  assert(req->srv == CO_GW_SRV_SET_HB);
2374 
2375  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2376  co_dev_t *dev = co_nmt_get_dev(nmt);
2377 
2378  if (__unlikely(req->size < sizeof(struct co_gw_req_set_hb))) {
2380  return -1;
2381  }
2382  const struct co_gw_req_set_hb *par =
2383  (const struct co_gw_req_set_hb *)req;
2384 
2385  co_unsigned32_t ac = 0;
2386 
2387  co_obj_t *obj = co_dev_find_obj(dev, 0x1017);
2388  if (__unlikely(!obj)) {
2389  ac = CO_SDO_AC_NO_OBJ;
2390  goto error;
2391  }
2392  co_sub_t *sub = co_obj_find_sub(obj, 0x00);
2393  if (__unlikely(!sub)) {
2394  ac = CO_SDO_AC_NO_SUB;
2395  goto error;
2396  }
2397  ac = co_sub_dn_ind_val(sub, CO_DEFTYPE_UNSIGNED16, &par->ms);
2398 
2399 error:
2400  return co_gw_send_con(gw, req, 0, ac);
2401 }
2402 
2403 static int
2404 co_gw_recv_set_id(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2405 {
2406  assert(gw);
2407  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2408  assert(req);
2409  assert(req->srv == CO_GW_SRV_SET_ID);
2410 
2411  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2412 
2413  if (__unlikely(req->size < sizeof(struct co_gw_req_node))) {
2415  return -1;
2416  }
2417  const struct co_gw_req_node *par = (const struct co_gw_req_node *)req;
2418 
2419  int iec = 0;
2420 
2421  // clang-format off
2422  if (__unlikely(!par->node
2423  || (par->node > CO_NUM_NODES && par->node != 0xff))) {
2424  // clang-format on
2425  iec = CO_GW_IEC_BAD_NODE;
2426  goto error;
2427  }
2428 
2429  co_nmt_set_id(nmt, par->node);
2430 
2431 error:
2432  return co_gw_send_con(gw, req, iec, 0);
2433 }
2434 
2435 #ifndef LELY_NO_CO_EMCY
2436 static int
2437 co_gw_recv_set_emcy(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
2438  const struct co_gw_req *req)
2439 {
2440  assert(gw);
2441  assert(req);
2442 
2443  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2444  co_dev_t *dev = co_nmt_get_dev(nmt);
2445 
2446  if (__unlikely(req->size < sizeof(struct co_gw_req_set_emcy))) {
2448  return -1;
2449  }
2450  const struct co_gw_req_set_emcy *par =
2451  (const struct co_gw_req_set_emcy *)req;
2452 
2453  co_unsigned32_t ac = 0;
2454 
2455  co_unsigned32_t cobid = par->cobid;
2456  if (par->srv == CO_GW_SRV_EMCY_START)
2458  else
2460 
2461  co_obj_t *obj = co_dev_find_obj(dev, 0x1028);
2462  if (__unlikely(!obj)) {
2463  ac = CO_SDO_AC_NO_OBJ;
2464  goto error;
2465  }
2466  co_sub_t *sub = co_obj_find_sub(obj, node);
2467  if (__unlikely(!sub)) {
2468  ac = CO_SDO_AC_NO_SUB;
2469  goto error;
2470  }
2472 
2473 error:
2474  return co_gw_send_con(gw, req, 0, ac);
2475 }
2476 #endif
2477 
2478 static int
2480 {
2481  assert(gw);
2482  assert(req);
2483  assert(req->srv == CO_GW_SRV_SET_CMD_TIMEOUT);
2484 
2485  if (__unlikely(req->size < sizeof(struct co_gw_req_set_cmd_timeout))) {
2487  return -1;
2488  }
2489  const struct co_gw_req_set_cmd_timeout *par =
2490  (const struct co_gw_req_set_cmd_timeout *)req;
2491 
2492  gw->timeout = par->timeout;
2493 
2494 #ifndef LELY_NO_CO_MASTER
2495  for (co_unsigned16_t id = 1; id <= CO_GW_NUM_NET; id++) {
2496  if (!gw->net[id - 1])
2497  continue;
2498  // Limit the NMT SDO timeout for each network by the global
2499  // gateway command timeout.
2500  int timeout = gw->net[id - 1]->timeout;
2501  if (gw->timeout)
2502  // clang-format off
2503  timeout = timeout
2504  ? MIN(timeout, gw->timeout)
2505  : gw->timeout;
2506  // clang-format on
2507  co_nmt_set_timeout(gw->net[id - 1]->nmt, timeout);
2508  }
2509 #endif
2510 
2511  return co_gw_send_con(gw, req, 0, 0);
2512 }
2513 
2514 static int
2516  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2517 {
2518  assert(gw);
2519  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2520  assert(req);
2521  assert(req->srv == CO_GW_SRV_SET_BOOTUP_IND);
2522 
2523  if (__unlikely(req->size < sizeof(struct co_gw_req_set_bootup_ind))) {
2525  return -1;
2526  }
2527  const struct co_gw_req_set_bootup_ind *par =
2528  (const struct co_gw_req_set_bootup_ind *)req;
2529 
2530  gw->net[net - 1]->bootup_ind = par->cs;
2531 
2532  return co_gw_send_con(gw, req, 0, 0);
2533 }
2534 
2535 static int
2536 co_gw_recv_set_net(co_gw_t *gw, const struct co_gw_req *req)
2537 {
2538  assert(gw);
2539  assert(req);
2540  assert(req->srv == CO_GW_SRV_SET_NET);
2541 
2542  if (__unlikely(req->size < sizeof(struct co_gw_req_net))) {
2544  return -1;
2545  }
2546  const struct co_gw_req_net *par = (const struct co_gw_req_net *)req;
2547 
2548  int iec = 0;
2549 
2550  if (__unlikely(par->net > CO_GW_NUM_NET)) {
2551  iec = CO_GW_IEC_BAD_NET;
2552  goto error;
2553  }
2554 
2555  gw->def = par->net;
2556 
2557 error:
2558  return co_gw_send_con(gw, req, iec, 0);
2559 }
2560 
2561 static int
2563  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2564 {
2565  assert(gw);
2566  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2567  assert(req);
2568  assert(req->srv == CO_GW_SRV_SET_NODE);
2569 
2570  if (__unlikely(req->size < sizeof(struct co_gw_req_node))) {
2572  return -1;
2573  }
2574  const struct co_gw_req_node *par = (const struct co_gw_req_node *)req;
2575 
2576  int iec = 0;
2577 
2578  if (__unlikely(par->node > CO_NUM_NODES)) {
2579  iec = CO_GW_IEC_BAD_NODE;
2580  goto error;
2581  }
2582 
2583  gw->net[net - 1]->def = par->node;
2584 
2585 error:
2586  return co_gw_send_con(gw, req, iec, 0);
2587 }
2588 
2589 static int
2591  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2592 {
2593  assert(gw);
2594  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2595  assert(req);
2596  assert(req->srv == CO_GW_SRV_GET_VERSION);
2597 
2598  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2599  co_dev_t *dev = co_nmt_get_dev(nmt);
2600 
2601  struct co_gw_con_get_version con = { .size = sizeof(con),
2602  .srv = req->srv,
2603  .data = req->data,
2604  .vendor_id = co_dev_get_val_u32(dev, 0x1018, 0x01),
2605  .product_code = co_dev_get_val_u32(dev, 0x1018, 0x02),
2606  .revision = co_dev_get_val_u32(dev, 0x1018, 0x03),
2607  .serial_nr = co_dev_get_val_u32(dev, 0x1018, 0x04),
2608  .gw_class = co_nmt_is_master(gw->net[net - 1]->nmt) ? 3 : 1,
2609  .prot_hi = CO_GW_PROT_HI,
2610  .prot_lo = CO_GW_PROT_LO };
2611  return co_gw_send_srv(gw, (struct co_gw_srv *)&con);
2612 }
2613 
2614 #if !defined(LELY_NO_CO_MASTER) && !defined(LELY_NO_CO_LSS)
2615 
2616 static int
2618  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2619 {
2620  assert(gw);
2621  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2622  assert(req);
2623  assert(req->srv == CO_GW_SRV_LSS_SWITCH);
2624 
2625  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2626  co_lss_t *lss = co_nmt_get_lss(nmt);
2627 
2628  if (__unlikely(req->size < sizeof(struct co_gw_req_lss_switch))) {
2630  return -1;
2631  }
2632  const struct co_gw_req_lss_switch *par =
2633  (const struct co_gw_req_lss_switch *)req;
2634 
2635  int iec = 0;
2636 
2637  if (__unlikely(!lss)) {
2638  iec = CO_GW_IEC_BAD_SRV;
2639  goto error;
2640  }
2641 
2642  int errc = get_errc();
2643  if (__unlikely(co_lss_switch_req(lss, par->mode) == -1)) {
2644  iec = errnum2iec(get_errnum());
2645  set_errc(errc);
2646  }
2647 
2648 error:
2649  return co_gw_send_con(gw, req, iec, 0);
2650 }
2651 
2652 static int
2654  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2655 {
2656  assert(gw);
2657  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2658  assert(req);
2659  assert(req->srv == CO_GW_SRV_LSS_SWITCH_SEL);
2660 
2661  if (__unlikely(req->size < sizeof(struct co_gw_req_lss_switch_sel))) {
2663  return -1;
2664  }
2665  const struct co_gw_req_lss_switch_sel *par =
2666  (const struct co_gw_req_lss_switch_sel *)req;
2667 
2668  int iec = 0;
2669  int errc = get_errc();
2670 
2671  struct co_gw_job *job = co_gw_job_create_lss(
2672  &gw->net[net - 1]->lss, gw->net[net - 1], req);
2673  if (__unlikely(!job)) {
2674  iec = errnum2iec(get_errnum());
2675  goto error_create_job;
2676  }
2677 
2678  // clang-format off
2679  if (__unlikely(co_lss_switch_sel_req(job->data, &par->id,
2680  &co_gw_job_lss_cs_ind, job) == -1)) {
2681  // clang-format on
2682  iec = errnum2iec(get_errnum());
2683  goto error_switch_sel_req;
2684  }
2685 
2686  return 0;
2687 
2688 error_switch_sel_req:
2689  co_gw_job_destroy(job);
2690 error_create_job:
2691  set_errc(errc);
2692  return co_gw_send_con(gw, req, iec, 0);
2693 }
2694 
2695 static int
2697  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2698 {
2699  assert(gw);
2700  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2701  assert(req);
2702  assert(req->srv == CO_GW_SRV_LSS_SET_ID);
2703 
2704  if (__unlikely(req->size < sizeof(struct co_gw_req_node))) {
2706  return -1;
2707  }
2708  const struct co_gw_req_node *par = (const struct co_gw_req_node *)req;
2709 
2710  int iec = 0;
2711  int errc = get_errc();
2712 
2713  struct co_gw_job *job = co_gw_job_create_lss(
2714  &gw->net[net - 1]->lss, gw->net[net - 1], req);
2715  if (__unlikely(!job)) {
2716  iec = errnum2iec(get_errnum());
2717  goto error_create_job;
2718  }
2719 
2720  // clang-format off
2721  if (__unlikely(co_lss_set_id_req(job->data, par->node,
2722  &co_gw_job_lss_err_ind, job) == -1)) {
2723  // clang-format on
2724  iec = errnum2iec(get_errnum());
2725  goto error_set_id_req;
2726  }
2727 
2728  return 0;
2729 
2730 error_set_id_req:
2731  co_gw_job_destroy(job);
2732 error_create_job:
2733  set_errc(errc);
2734  return co_gw_send_con(gw, req, iec, 0);
2735 }
2736 
2737 static int
2739  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2740 {
2741  assert(gw);
2742  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2743  assert(req);
2744  assert(req->srv == CO_GW_SRV_LSS_SET_RATE);
2745 
2746  if (__unlikely(req->size < sizeof(struct co_gw_req_lss_set_rate))) {
2748  return -1;
2749  }
2750  const struct co_gw_req_lss_set_rate *par =
2751  (const struct co_gw_req_lss_set_rate *)req;
2752 
2753  int iec = 0;
2754 
2755  if (__unlikely(par->bitsel)) {
2756  iec = CO_GW_IEC_LSS_RATE;
2757  goto error_srv;
2758  }
2759 
2760  co_unsigned16_t rate;
2761  switch (par->bitidx) {
2762  case 0: rate = 1000; break;
2763  case 1: rate = 800; break;
2764  case 2: rate = 500; break;
2765  case 3: rate = 250; break;
2766  case 4: rate = 125; break;
2767  case 6: rate = 50; break;
2768  case 7: rate = 20; break;
2769  case 8: rate = 10; break;
2770  case 9: rate = 0; break;
2771  default: iec = CO_GW_IEC_LSS_RATE; goto error_srv;
2772  }
2773 
2774  int errc = get_errc();
2775 
2776  struct co_gw_job *job = co_gw_job_create_lss(
2777  &gw->net[net - 1]->lss, gw->net[net - 1], req);
2778  if (__unlikely(!job)) {
2779  iec = errnum2iec(get_errnum());
2780  goto error_create_job;
2781  }
2782 
2783  // clang-format off
2784  if (__unlikely(co_lss_set_rate_req(job->data, rate,
2785  &co_gw_job_lss_err_ind, job) == -1)) {
2786  // clang-format on
2787  iec = errnum2iec(get_errnum());
2788  goto error_set_rate_req;
2789  }
2790 
2791  return 0;
2792 
2793 error_set_rate_req:
2794  co_gw_job_destroy(job);
2795 error_create_job:
2796  set_errc(errc);
2797 error_srv:
2798  return co_gw_send_con(gw, req, iec, 0);
2799 }
2800 
2801 static int
2803  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2804 {
2805  assert(gw);
2806  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2807  assert(req);
2808  assert(req->srv == CO_GW_SRV_LSS_SWITCH_RATE);
2809 
2810  co_nmt_t *nmt = gw->net[net - 1]->nmt;
2811  co_lss_t *lss = co_nmt_get_lss(nmt);
2812 
2813  if (__unlikely(req->size < sizeof(struct co_gw_req_lss_switch_rate))) {
2815  return -1;
2816  }
2817  const struct co_gw_req_lss_switch_rate *par =
2818  (const struct co_gw_req_lss_switch_rate *)req;
2819 
2820  int iec = 0;
2821 
2822  if (__unlikely(!lss)) {
2823  iec = CO_GW_IEC_BAD_SRV;
2824  goto error;
2825  }
2826 
2827  int errc = get_errc();
2828  if (__unlikely(co_lss_switch_rate_req(lss, par->delay) == -1)) {
2829  iec = errnum2iec(get_errnum());
2830  set_errc(errc);
2831  }
2832 
2833 error:
2834  return co_gw_send_con(gw, req, iec, 0);
2835 }
2836 
2837 static int
2839  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2840 {
2841  assert(gw);
2842  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2843  assert(req);
2844  assert(req->srv == CO_GW_SRV_LSS_STORE);
2845 
2846  int iec = 0;
2847  int errc = get_errc();
2848 
2849  struct co_gw_job *job = co_gw_job_create_lss(
2850  &gw->net[net - 1]->lss, gw->net[net - 1], req);
2851  if (__unlikely(!job)) {
2852  iec = errnum2iec(get_errnum());
2853  goto error_create_job;
2854  }
2855 
2856  // clang-format off
2858  == -1)) {
2859  // clang-format on
2860  iec = errnum2iec(get_errnum());
2861  goto error_store_req;
2862  }
2863 
2864  return 0;
2865 
2866 error_store_req:
2867  co_gw_job_destroy(job);
2868 error_create_job:
2869  set_errc(errc);
2870  return co_gw_send_con(gw, req, iec, 0);
2871 }
2872 
2873 static int
2875  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2876 {
2877  assert(gw);
2878  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2879  assert(req);
2880  assert(req->srv == CO_GW_SRV_LSS_GET_LSSID);
2881 
2882  if (__unlikely(req->size < sizeof(struct co_gw_req_lss_get_lssid))) {
2884  return -1;
2885  }
2886  const struct co_gw_req_lss_get_lssid *par =
2887  (const struct co_gw_req_lss_get_lssid *)req;
2888 
2889  int iec = 0;
2890  int errc = get_errc();
2891 
2892  struct co_gw_job *job = co_gw_job_create_lss(
2893  &gw->net[net - 1]->lss, gw->net[net - 1], req);
2894  if (__unlikely(!job)) {
2895  iec = errnum2iec(get_errnum());
2896  goto error_create_job;
2897  }
2898 
2899  switch (par->cs) {
2900  case 0x5a:
2901  // clang-format off
2903  &co_gw_job_lss_lssid_ind, job) == -1)) {
2904  // clang-format on
2905  iec = errnum2iec(get_errnum());
2906  goto error_switch_sel_req;
2907  }
2908  break;
2909  case 0x5b:
2910  // clang-format off
2912  &co_gw_job_lss_lssid_ind, job) == -1)) {
2913  // clang-format on
2914  iec = errnum2iec(get_errnum());
2915  goto error_switch_sel_req;
2916  }
2917  break;
2918  case 0x5c:
2919  // clang-format off
2921  &co_gw_job_lss_lssid_ind, job) == -1)) {
2922  // clang-format on
2923  iec = errnum2iec(get_errnum());
2924  goto error_switch_sel_req;
2925  }
2926  break;
2927  case 0x5d:
2928  // clang-format off
2930  &co_gw_job_lss_lssid_ind, job) == -1)) {
2931  // clang-format on
2932  iec = errnum2iec(get_errnum());
2933  goto error_switch_sel_req;
2934  }
2935  break;
2936  default: iec = CO_GW_IEC_LSS; goto error_cs;
2937  }
2938 
2939  return 0;
2940 
2941 error_switch_sel_req:
2942 error_cs:
2943  co_gw_job_destroy(job);
2944 error_create_job:
2945  set_errc(errc);
2946  return co_gw_send_con(gw, req, iec, 0);
2947 }
2948 
2949 static int
2951  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2952 {
2953  assert(gw);
2954  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2955  assert(req);
2956  assert(req->srv == CO_GW_SRV_LSS_GET_ID);
2957 
2958  int iec = 0;
2959  int errc = get_errc();
2960 
2961  struct co_gw_job *job = co_gw_job_create_lss(
2962  &gw->net[net - 1]->lss, gw->net[net - 1], req);
2963  if (__unlikely(!job)) {
2964  iec = errnum2iec(get_errnum());
2965  goto error_create_job;
2966  }
2967 
2968  // clang-format off
2970  == -1)) {
2971  // clang-format on
2972  iec = errnum2iec(get_errnum());
2973  goto error_get_id_req;
2974  }
2975 
2976  return 0;
2977 
2978 error_get_id_req:
2979  co_gw_job_destroy(job);
2980 error_create_job:
2981  set_errc(errc);
2982  return co_gw_send_con(gw, req, iec, 0);
2983 }
2984 
2985 static int
2987  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2988 {
2989  assert(gw);
2990  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2991  assert(req);
2992  assert(req->srv == CO_GW_SRV_LSS_ID_SLAVE);
2993 
2994  if (__unlikely(req->size < sizeof(struct co_gw_req_lss_id_slave))) {
2996  return -1;
2997  }
2998  const struct co_gw_req_lss_id_slave *par =
2999  (const struct co_gw_req_lss_id_slave *)req;
3000 
3001  int iec = 0;
3002  int errc = get_errc();
3003 
3004  struct co_gw_job *job = co_gw_job_create_lss(
3005  &gw->net[net - 1]->lss, gw->net[net - 1], req);
3006  if (__unlikely(!job)) {
3007  iec = errnum2iec(get_errnum());
3008  goto error_create_job;
3009  }
3010 
3011  // clang-format off
3012  if (__unlikely(co_lss_id_slave_req(job->data, &par->lo, &par->hi,
3013  &co_gw_job_lss_cs_ind, job) == -1)) {
3014  // clang-format on
3015  iec = errnum2iec(get_errnum());
3016  goto error_id_slave_req;
3017  }
3018 
3019  return 0;
3020 
3021 error_id_slave_req:
3022  co_gw_job_destroy(job);
3023 error_create_job:
3024  set_errc(errc);
3025  return co_gw_send_con(gw, req, iec, 0);
3026 }
3027 
3028 static int
3030  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
3031 {
3032  assert(gw);
3033  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
3034  assert(req);
3036 
3037  int iec = 0;
3038  int errc = get_errc();
3039 
3040  struct co_gw_job *job = co_gw_job_create_lss(
3041  &gw->net[net - 1]->lss, gw->net[net - 1], req);
3042  if (__unlikely(!job)) {
3043  iec = errnum2iec(get_errnum());
3044  goto error_create_job;
3045  }
3046 
3047  // clang-format off
3049  job->data, &co_gw_job_lss_cs_ind, job) == -1)) {
3050  // clang-format on
3051  iec = errnum2iec(get_errnum());
3052  goto error_id_non_cfg_slave_req;
3053  }
3054 
3055  return 0;
3056 
3057 error_id_non_cfg_slave_req:
3058  co_gw_job_destroy(job);
3059 error_create_job:
3060  set_errc(errc);
3061  return co_gw_send_con(gw, req, iec, 0);
3062 }
3063 
3064 static int
3066  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
3067 {
3068  assert(gw);
3069  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
3070  assert(req);
3071  assert(req->srv == CO_GW_SRV__LSS_SLOWSCAN);
3072 
3073  if (__unlikely(req->size < sizeof(struct co_gw_req__lss_scan))) {
3075  return -1;
3076  }
3077  const struct co_gw_req__lss_scan *par =
3078  (const struct co_gw_req__lss_scan *)req;
3079 
3080  int iec = 0;
3081  int errc = get_errc();
3082 
3083  struct co_gw_job *job = co_gw_job_create_lss(
3084  &gw->net[net - 1]->lss, gw->net[net - 1], req);
3085  if (__unlikely(!job)) {
3086  iec = errnum2iec(get_errnum());
3087  goto error_create_job;
3088  }
3089 
3090  // clang-format off
3091  if (__unlikely(co_lss_slowscan_req(job->data, &par->id_1, &par->id_2,
3092  &co_gw_job_lss_scan_ind, job) == -1)) {
3093  // clang-format on
3094  iec = errnum2iec(get_errnum());
3095  goto error_slowscan_req;
3096  }
3097 
3098  return 0;
3099 
3100 error_slowscan_req:
3101  co_gw_job_destroy(job);
3102 error_create_job:
3103  set_errc(errc);
3104  return co_gw_send_con(gw, req, iec, 0);
3105 }
3106 
3107 static int
3109  co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
3110 {
3111  assert(gw);
3112  assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
3113  assert(req);
3114  assert(req->srv == CO_GW_SRV__LSS_FASTSCAN);
3115 
3116  if (__unlikely(req->size < sizeof(struct co_gw_req__lss_scan))) {
3118  return -1;
3119  }
3120  const struct co_gw_req__lss_scan *par =
3121  (const struct co_gw_req__lss_scan *)req;
3122 
3123  int iec = 0;
3124  int errc = get_errc();
3125 
3126  struct co_gw_job *job = co_gw_job_create_lss(
3127  &gw->net[net - 1]->lss, gw->net[net - 1], req);
3128  if (__unlikely(!job)) {
3129  iec = errnum2iec(get_errnum());
3130  goto error_create_job;
3131  }
3132 
3133  // clang-format off
3134  if (__unlikely(co_lss_fastscan_req(job->data, &par->id_1, &par->id_2,
3135  &co_gw_job_lss_scan_ind, job) == -1)) {
3136  // clang-format on
3137  iec = errnum2iec(get_errnum());
3138  goto error_fastscan_req;
3139  }
3140 
3141  return 0;
3142 
3143 error_fastscan_req:
3144  co_gw_job_destroy(job);
3145 error_create_job:
3146  set_errc(errc);
3147  return co_gw_send_con(gw, req, iec, 0);
3148 }
3149 
3150 #endif // !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
3151 
3152 static int
3153 co_gw_send_con(co_gw_t *gw, const struct co_gw_req *req, int iec,
3154  co_unsigned32_t ac)
3155 {
3156  assert(req);
3157 
3158  // Convert SDO abort codes to their equivalent internal error codes
3159  // where possible.
3160  switch (ac) {
3161  case CO_SDO_AC_TIMEOUT:
3162  ac = 0;
3163  iec = CO_GW_IEC_TIMEOUT;
3164  break;
3165  case CO_SDO_AC_NO_MEM:
3166  ac = 0;
3167  iec = CO_GW_IEC_NO_MEM;
3168  break;
3169  case CO_SDO_AC_PDO_LEN: ac = 0; iec = CO_GW_IEC_PDO_LEN;
3170  }
3171 
3172  // Copy the service number and user-specified data from the request to
3173  // the confirmation.
3174  struct co_gw_con con = { .size = sizeof(con),
3175  .srv = req->srv,
3176  .data = req->data,
3177  .iec = iec,
3178  .ac = ac };
3179  return co_gw_send_srv(gw, (struct co_gw_srv *)&con);
3180 }
3181 
3182 static int
3183 co_gw_send_ec(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
3184  co_unsigned8_t st, int iec)
3185 {
3186  struct co_gw_ind_ec ind = { .size = sizeof(ind),
3187  .srv = CO_GW_SRV_EC,
3188  .net = net,
3189  .node = node,
3190  .st = st,
3191  .iec = iec };
3192  return co_gw_send_srv(gw, (struct co_gw_srv *)&ind);
3193 }
3194 
3195 static int
3197 {
3198  assert(gw);
3199  assert(srv);
3200 
3201  if (__unlikely(!gw->send_func)) {
3203  return -1;
3204  }
3205 
3206  return gw->send_func(srv, gw->send_data) ? -1 : 0;
3207 }
3208 
3209 static inline int
3211 {
3212  switch (errnum) {
3213  case 0: return 0;
3214  case ERRNUM_INVAL: return CO_GW_IEC_SYNTAX;
3215  case ERRNUM_NOMEM: return CO_GW_IEC_NO_MEM;
3216  case ERRNUM_PERM: return CO_GW_IEC_BAD_SRV;
3217  default: return CO_GW_IEC_INTERN;
3218  }
3219 }
3220 
3221 #endif // !LELY_NO_CO_GW
size_t size
The size of this struct (in bytes).
Definition: gw.h:859
#define CO_GW_SRV_LSS_SET_RATE
CANopen gateway service: LSS configure bit-rate.
Definition: gw.h:137
co_unsigned16_t net
The network-ID.
Definition: gw.h:465
int srv
The service number.
Definition: gw.h:275
co_unsigned16_t net
The network-ID.
Definition: gw.h:879
void co_rpdo_set_ind(co_rpdo_t *pdo, co_rpdo_ind_t *ind, void *data)
Sets the indication function invoked when a Receive-PDO error occurs.
Definition: rpdo.c:366
int co_nmt_cs_req(co_nmt_t *nmt, co_unsigned8_t cs, co_unsigned8_t id)
Submits an NMT request to a slave.
Definition: nmt.c:1455
A CANopen SDO upload/download request.
Definition: sdo.h:178
A PDO mapping parameter record.
Definition: pdo.h:69
int co_nmt_set_id(co_nmt_t *nmt, co_unsigned8_t id)
Sets the pending node-ID.
Definition: nmt.c:1400
#define CO_GW_IEC_CAN_PASSIVE
CANopen gateway internal error: Error passive.
Definition: gw.h:218
size_t size
The size of this struct (in bytes).
Definition: gw.h:949
int srv
The service number (CO_GW_SRV_EMCY_START or CO_GW_SRV_EMCY_STOP).
Definition: gw.h:523
co_sync_t * co_nmt_get_sync(const co_nmt_t *nmt)
Returns a pointer to the SYNC producer/consumer service.
Definition: nmt.c:1831
#define CO_GW_IEC_HB_RESOLVED
CANopen gateway internal error: Heartbeat started.
Definition: gw.h:206
static void co_gw_net_ng_ind(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason, void *data)
The callback function invoked when a node guarding event occurs for a node on a CANopen network...
Definition: gw.c:1144
struct co_gw_net * net[CO_GW_NUM_NET]
An array of pointers to the CANopen networks.
Definition: gw.c:309
size_t size
The size of this struct (in bytes).
Definition: gw.h:438
int co_lss_set_id_req(co_lss_t *lss, co_unsigned8_t id, co_lss_err_ind_t *ind, void *data)
Requests the &#39;configure node-ID&#39; service.
Definition: lss.c:893
int co_gw_send_func_t(const struct co_gw_srv *srv, void *data)
The type of a CANopen gateway send callback function, invoked by a gateway when an indication or conf...
Definition: gw.h:976
int co_lss_get_revision_req(co_lss_t *lss, co_lss_lssid_ind_t *ind, void *data)
Requests the &#39;inquire identity revision-number&#39; service.
Definition: lss.c:1067
co_unsigned8_t node
The node-ID.
Definition: gw.h:865
#define CO_EMCY_COBID_VALID
The bit in the EMCY COB-ID specifying whether the EMCY exists and is valid.
Definition: emcy.h:29
The parameters of a CANopen gateway &#39;LSS inquire node-ID&#39; confirmation.
Definition: gw.h:797
#define CO_GW_IEC_HB_OCCURRED
CANopen gateway internal error: Heartbeat lost.
Definition: gw.h:209
static int co_gw_recv_lss_id_slave(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;LSS identify remote slave&#39; request.
Definition: gw.c:2986
#define CO_BAUD_20
A bit rate of 20 kbit/s.
Definition: dev.h:77
#define CO_GW_NUM_NET
The maximum number of networks in a CANopen gateway.
Definition: gw.h:29
void co_csdo_set_timeout(co_csdo_t *sdo, int timeout)
Sets the timeout of a Client-SDO.
Definition: csdo.c:944
co_unsigned16_t gt
The guard time (in milliseconds).
Definition: gw.h:469
A CANopen LSS master/slave service.
Definition: lss.c:43
static void co_gw_net_st_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, void *data)
The callback function invoked when a boot-up event or state change is detected for a node on a CANope...
Definition: gw.c:1200
int co_dev_dn_req(co_dev_t *dev, 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 local device.
Definition: csdo.c:600
co_unsigned32_t co_sub_dn_ind_val(co_sub_t *sub, co_unsigned16_t type, const void *val)
Invokes the download indication function of a CANopen sub-object, registered with co_sub_set_dn_ind()...
Definition: obj.c:810
int co_lss_set_rate_req(co_lss_t *lss, co_unsigned16_t rate, co_lss_err_ind_t *ind, void *data)
Requests the &#39;configure bit timing parameters&#39; service.
Definition: lss.c:925
co_unsigned8_t subidx
The object sub-index.
Definition: gw.h:341
void co_gw_get_rate_func(const co_gw_t *gw, co_gw_rate_func_t **pfunc, void **pdata)
Retrieves the callback function invoked when a baudrate switch is needed after an &#39;Initialize gateway...
Definition: gw.c:925
co_unsigned32_t cobid
The COB-ID.
Definition: gw.h:378
static int co_gw_recv_lss_set_rate(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;LSS configure bit-rate&#39; request.
Definition: gw.c:2738
int co_gw_init_net(co_gw_t *gw, co_unsigned16_t id, co_nmt_t *nmt)
Registers a CANopen network with a gateway.
Definition: gw.c:573
#define CO_GW_IEC_BOOTUP
CANopen gateway internal error: Boot-up.
Definition: gw.h:215
const struct co_pdo_comm_par * co_rpdo_get_comm_par(const co_rpdo_t *pdo)
Returns a pointer to the PDO communication parameter record of a Receive-PDO.
Definition: rpdo.c:339
#define CO_NMT_CS_STOP
The NMT command specifier &#39;stop&#39;.
Definition: nmt.h:43
The parameters of a CANopen gateway &#39;Set heartbeat producer&#39; request.
Definition: gw.h:505
co_unsigned16_t ms
The heartbeat time (in milliseconds).
Definition: gw.h:515
An NMT error control event was resolved.
Definition: nmt.h:82
#define CO_GW_SRV_NMT_RESET_NODE
CANopen gateway service: Reset node.
Definition: gw.h:71
#define CO_BAUD_10
A bit rate of 10 kbit/s.
Definition: dev.h:80
co_unsigned32_t co_dev_cfg_hb(co_dev_t *dev, co_unsigned8_t id, co_unsigned16_t ms)
Configures heartbeat consumption for the specified node by updating CANopen object 1016 (Consumer hea...
Definition: nmt.c:637
#define CO_NMT_ST_START
The NMT state &#39;operational&#39;.
Definition: nmt.h:61
co_unsigned8_t ltf
The lifetime factor.
Definition: gw.h:471
static struct co_gw_net * co_gw_net_create(co_gw_t *gw, co_unsigned16_t id, co_nmt_t *nmt)
Creates a new CANopen network.
Definition: gw.c:945
A CANopen sub-object.
Definition: obj.h:54
co_gw_t * co_gw_create(void)
Creates a new CANopen gateway.
Definition: gw.c:539
int srv
The service number (CO_GW_SRV__SYNC).
Definition: gw.h:921
static void co_gw_job_sdo_ind(const co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
The progress indication function for an SDO upload/download job.
Definition: gw.c:1511
static int co_gw_recv_set_id(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a &#39;Set node-ID&#39; request.
Definition: gw.c:2404
#define CO_GW_SRV_INIT
CANopen gateway service: Initialize gateway.
Definition: gw.h:95
co_nmt_sdo_ind_t * dn_ind
A pointer to the original SDO download progress indication function.
Definition: gw.c:114
A CANopen Receive-PDO.
Definition: rpdo.c:40
co_unsigned64_t val[0x40]
An array of object values.
Definition: gw.h:746
#define CO_GW_SRV_SET_BOOTUP_IND
CANopen gateway service: Boot-up forwarding.
Definition: gw.h:113
void co_gw_destroy(co_gw_t *gw)
Destroys a CANopen gateway.
Definition: gw.c:564
size_t size
The size of this struct (in bytes).
Definition: gw.h:799
#define CO_GW_SRV_EMCY_START
CANopen gateway service: Start emergency consumer.
Definition: gw.h:104
co_unsigned8_t trans
The transmission type.
Definition: gw.h:405
An NMT error control event occurred.
Definition: nmt.h:80
int srv
The service number (CO_GW_SRV_SDO).
Definition: gw.h:898
#define CO_GW_REQ_SET_RPDO_SIZE
The minimum size (in bytes) of a CANopen gateway &#39;Configure RPDO&#39; request.
Definition: gw.h:388
co_unsigned32_t map[0x40]
An array of objects to be mapped.
Definition: gw.h:415
This header file is part of the CANopen library; it contains the Transmit-PDO declarations.
#define CO_BAUD_500
A bit rate of 500 kbit/s.
Definition: dev.h:65
The parameters of a CANopen gateway &#39;Initialize gateway&#39; request.
Definition: gw.h:491
struct co_gw_net * net
A pointer to the CANopen network.
Definition: gw.c:239
void co_nmt_get_hb_ind(const co_nmt_t *nmt, co_nmt_hb_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a heartbeat event occurs.
Definition: nmt.c:1138
co_unsigned16_t num
The PDO number.
Definition: gw.h:432
int srv
The service number (CO_GW_SRV_LSS_GET_LSSID).
Definition: gw.h:638
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition: errnum.c:825
static int co_gw_recv_nmt_cs(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, co_unsigned8_t cs, const struct co_gw_req *req)
Processes an NMT request.
Definition: gw.c:2176
static void co_gw_net_time_ind(co_time_t *time, const struct timespec *tp, void *data)
The callback function invoked when a TIME message is received from a node on a CANopen network...
Definition: gw.c:1307
size_t size
The size of this struct (in bytes).
Definition: gw.h:896
#define CO_GW_SRV__LSS_FASTSCAN
Lely-specific gateway service: LSS Fastscan.
Definition: gw.h:164
#define CO_GW_SRV_LSS_STORE
CANopen gateway service: LSS store configuration.
Definition: gw.h:143
co_unsigned8_t mode
0 for waiting state, 1 for configuration state.
Definition: gw.h:586
The parameters of a CANopen gateway &#39;Inquire LSS address&#39; request.
Definition: gw.h:634
co_nmt_sdo_ind_t * up_ind
A pointer to the original SDO upload progress indication function.
Definition: gw.c:118
#define CO_GW_SRV_SET_ID
CANopen gateway service: Set node-ID.
Definition: gw.h:101
struct co_gw_req req
The service parameters of the request.
Definition: gw.c:245
int srv
The service number (CO_GW_SRV__LSS_SLOWSCAN or CO_GW_SRV__LSS_FASTSCAN).
Definition: gw.h:823
A CANopen gateway.
Definition: gw.c:307
A CANopen Transmit-PDO.
Definition: tpdo.c:41
The parameters of a CANopen gateway &#39;SDO download&#39; request.
Definition: gw.h:327
#define CO_GW_SRV_NMT_NG_DISABLE
CANopen gateway service: Disable node guarding.
Definition: gw.h:80
#define CO_GW_IND_RPDO_SIZE
The minimum size (in bytes) of a CANopen gateway &#39;RPDO received&#39; indication.
Definition: gw.h:851
static void co_gw_job_lss_scan_ind(co_lss_t *lss, co_unsigned8_t cs, const struct co_id *id, void *data)
The confirmation function for an &#39;LSS Slowscan/Fastscan&#39; request.
Definition: gw.c:1700
#define CO_GW_SRV_SET_TPDO
CANopen gateway service: Configure TPDO.
Definition: gw.h:50
The parameters of a CANopen gateway &#39;SDO upload&#39; confirmation.
Definition: gw.h:705
co_gw_rate_func_t * rate_func
A pointer to the callback function invoked when a baudrate switch is needed after an &#39;Initialize gate...
Definition: gw.c:325
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
static int co_gw_recv_lss_get_id(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;LSS inquire node-ID&#39; request.
Definition: gw.c:2950
int co_dev_up_req(const co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx, co_csdo_up_con_t *con, void *data)
Submits an upload request to a local device.
Definition: csdo.c:675
int co_lss_id_slave_req(co_lss_t *lss, const struct co_id *lo, const struct co_id *hi, co_lss_cs_ind_t *ind, void *data)
Requests the &#39;LSS identify remote slave&#39; service.
Definition: lss.c:1144
int co_gw_recv(co_gw_t *gw, const struct co_gw_req *req)
Receives and processes a request with a CANopen gateway.
Definition: gw.c:604
co_unsigned8_t n
Number of mapped objects in PDO.
Definition: pdo.h:71
co_lss_t * co_nmt_get_lss(const co_nmt_t *nmt)
Returns a pointer to the LSS master/slave service.
Definition: nmt.c:1855
int co_lss_slowscan_req(co_lss_t *lss, const struct co_id *lo, const struct co_id *hi, co_lss_scan_ind_t *ind, void *data)
Requests the &#39;LSS Slowscan&#39; service.
Definition: lss.c:1194
void * data
A pointer to user-specified data.
Definition: gw.h:313
#define LELY_CO_LSS_TIMEOUT
The default LSS timeout (in milliseconds).
Definition: lss.h:30
#define CO_GW_SRV_SDO_DN
CANopen gateway service: SDO download.
Definition: gw.h:41
static int co_gw_recv_pdo_write(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a &#39;Write PDO data&#39; request.
Definition: gw.c:2112
int co_nmt_cs_ind(co_nmt_t *nmt, co_unsigned8_t cs)
Processes an NMT command from the master or the application.
Definition: nmt.c:1710
static int co_gw_send_srv(co_gw_t *gw, const struct co_gw_srv *srv)
Invokes the callback function to send a confirmation or indication.
Definition: gw.c:3196
The parameters of a CANopen gateway &#39;LSS switch state global&#39; request.
Definition: gw.h:576
#define CO_GW_IEC_INTERN
CANopen gateway internal error: Request not processed due to internal state.
Definition: gw.h:182
#define CO_GW_IEC_NO_DEF_NET
CANopen gateway internal error: No default net set.
Definition: gw.h:188
A PDO communication parameter record.
Definition: pdo.h:43
#define CO_GW_IEC_BAD_NET
CANopen gateway internal error: Unsupported net.
Definition: gw.h:194
co_unsigned8_t sync
The SYNC start value.
Definition: gw.h:411
void co_nmt_set_hb_ind(co_nmt_t *nmt, co_nmt_hb_ind_t *ind, void *data)
Sets the indication function invoked when a heartbeat event occurs.
Definition: nmt.c:1149
size_t size
The size of this struct (in bytes).
Definition: gw.h:875
#define CO_GW_IEC_PDO_INUSE
CANopen gateway internal error: PDO already used.
Definition: gw.h:233
co_unsigned8_t node
The node-ID.
Definition: gw.h:303
#define CO_GW_SRV_PDO_WRITE
CANopen gateway service: Write PDO data.
Definition: gw.h:56
int co_lss_switch_sel_req(co_lss_t *lss, const struct co_id *id, co_lss_cs_ind_t *ind, void *data)
Requests the &#39;switch state selective&#39; service.
Definition: lss.c:869
void co_nmt_set_dn_ind(co_nmt_t *nmt, co_nmt_sdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO download requ...
Definition: nmt.c:1294
#define CO_GW_REQ_SET_TPDO_SIZE
The minimum size (in bytes) of a CANopen gateway &#39;Configure TPDO&#39; request.
Definition: gw.h:419
void * ng_data
A pointer to user-specified data for ng_ind.
Definition: gw.c:94
co_unsigned8_t co_dev_get_id(const co_dev_t *dev)
Returns the node-ID of a CANopen device.
Definition: dev.c:198
#define MIN(a, b)
Returns the minimum of a and b.
Definition: util.h:57
struct co_gw_job * lss
A pointer to the LSS job.
Definition: gw.c:84
static int co_gw_send_ec(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, co_unsigned8_t st, int iec)
Sends an &#39;Error control event received&#39; indication.
Definition: gw.c:3183
The parameters of a CANopen gateway &#39;Configure SDO time-out&#39; request.
Definition: gw.h:352
#define CO_GW_SRV_GET_VERSION
CANopen gateway service: Get version.
Definition: gw.h:122
void * boot_data
A pointer to user-specified data for boot_ind.
Definition: gw.c:112
co_unsigned8_t bitidx
The bit timing index (in the range [0..9]).
Definition: gw.h:501
static void co_gw_net_up_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned16_t idx, co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
The callback function invoked to notify the user of the progress of an SDO upload request during the ...
Definition: gw.c:1265
void co_gw_rate_func_t(co_unsigned16_t net, co_unsigned16_t rate, void *data)
The type of a CANopen gateway &#39;set bit timing&#39; function, invoked when a baudrate switch is needed aft...
Definition: gw.h:986
static int co_gw_recv__lss_fastscan(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;LSS Fastscan&#39; request.
Definition: gw.c:3108
co_unsigned16_t num
The PDO number.
Definition: gw.h:446
co_unsigned8_t bitidx
The bit timing index.
Definition: gw.h:616
#define CO_GW_IEC_ST_OCCURRED
CANopen gateway internal error: Wrong NMT state.
Definition: gw.h:212
#define CO_BAUD_50
A bit rate of 50 kbit/s.
Definition: dev.h:74
This header file is part of the CANopen library; it contains the Client-SDO declarations.
The parameters of a Lely-specific gateway &#39;LSS Slowscan/Fastscan&#39; confirmation.
Definition: gw.h:816
The parameters of a CANopen gateway &#39;Read PDO&#39; confirmation.
Definition: gw.h:728
void co_nmt_set_ng_ind(co_nmt_t *nmt, co_nmt_ng_ind_t *ind, void *data)
Sets the indication function invoked when a node guarding event occurs.
Definition: nmt.c:1085
int co_lss_get_product_code_req(co_lss_t *lss, co_lss_lssid_ind_t *ind, void *data)
Requests the &#39;inquire identity product-code&#39; service.
Definition: lss.c:1042
static int co_gw_recv__lss_slowscan(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;LSS Slowscan&#39; request.
Definition: gw.c:3065
This header file is part of the CANopen library; it contains the Service Data Object (SDO) declaratio...
co_unsigned16_t net
The network-ID.
Definition: gw.h:584
The parameters of a CANopen gateway &#39;Read PDO&#39; request.
Definition: gw.h:422
co_nmt_ng_ind_t * ng_ind
A pointer to the original node guarding event indication function.
Definition: gw.c:92
int co_gw_fini_net(co_gw_t *gw, co_unsigned16_t id)
Unregisters a CANopen network with a gateway.
Definition: gw.c:588
The parameters of a CANopen gateway &#39;Error control event received&#39; indication.
Definition: gw.h:857
co_gw_t * gw
A pointer to the CANopen gateway.
Definition: gw.c:62
The parameters of a CANopen gateway &#39;Emergency event received&#39; indication.
Definition: gw.h:873
#define CO_GW_IEC_LG_OCCURRED
CANopen gateway internal error: Lost connection.
Definition: gw.h:203
#define CO_PDO_MAP_PAR_INIT
The static initializer from struct co_pdo_map_par.
Definition: pdo.h:78
int co_nmt_ng_req(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned16_t gt, co_unsigned8_t ltf)
Request the node guarding service for the specified node, even if it is not in the network list...
Definition: nmt.c:1662
size_t size
The size of this struct (in bytes).
Definition: gw.h:934
co_unsigned16_t ms
The heartbeat time (in milliseconds).
Definition: gw.h:487
The parameters of a CANopen gateway &#39;Get version&#39; confirmation.
Definition: gw.h:753
static int co_gw_recv_set_rpdo(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a &#39;Configure RPDO&#39; request.
Definition: gw.c:1960
size_t size
The size of this struct (in bytes).
Definition: gw.h:309
struct co_id lo
The lower bound of the LSS address.
Definition: gw.h:658
co_unsigned16_t type
The data type.
Definition: gw.h:323
co_unsigned16_t net
The network-ID.
Definition: gw.h:360
co_unsigned32_t ac
The SDO abort code (0 on success).
Definition: gw.h:829
#define CO_GW_IEC_LSS_RATE
CANopen gateway internal error: LSS bit-rate not supported.
Definition: gw.h:245
int timeout
The command timeout (in milliseconds).
Definition: gw.c:311
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
int co_lss_switch_rate_req(co_lss_t *lss, int delay)
Requests the &#39;activate bit timing parameters&#39; service.
Definition: lss.c:966
co_unsigned16_t net
The network-ID.
Definition: gw.h:499
#define CO_GW_SRV_NMT_ENTER_PREOP
CANopen gateway service: Set node to pre-operational.
Definition: gw.h:68
co_unsigned32_t co_pdo_map(const struct co_pdo_map_par *par, const co_unsigned64_t *val, co_unsigned8_t n, uint8_t *buf, size_t *pn)
Maps values into a PDO.
Definition: pdo.c:192
co_unsigned16_t net
The network-ID.
Definition: gw.h:938
int iec
The internal error code (0 on success).
Definition: gw.h:869
#define CO_GW_SRV_NMT_STOP
CANopen gateway service: Start node.
Definition: gw.h:65
unsigned bootup_ind
A flag indicating whether "boot-up event received" commands should be forwarded (1) or not (0)...
Definition: gw.c:77
static int co_gw_recv_set_net(co_gw_t *gw, const struct co_gw_req *req)
Processes a &#39;Set default network&#39; request.
Definition: gw.c:2536
co_unsigned16_t co_rpdo_get_num(const co_rpdo_t *pdo)
Returns the PDO number of a Receive-PDO.
Definition: rpdo.c:331
static void co_gw_job_lss_err_ind(co_lss_t *lss, co_unsigned8_t cs, co_unsigned8_t err, co_unsigned8_t spec, void *data)
The confirmation function for an &#39;LSS configure node-ID&#39;, &#39;LSS configure bit-rate&#39; or &#39;LSS store conf...
Definition: gw.c:1599
struct co_id id
The LSS address of the slave to be configured.
Definition: gw.h:600
int co_lss_get_serial_nr_req(co_lss_t *lss, co_lss_lssid_ind_t *ind, void *data)
Requests the &#39;inquire identity serial-number&#39; service.
Definition: lss.c:1093
static void co_gw_job_lss_lssid_ind(co_lss_t *lss, co_unsigned8_t cs, co_unsigned32_t id, void *data)
The confirmation function for an &#39;Inquire LSS address&#39; request.
Definition: gw.c:1634
co_unsigned8_t bitsel
The bit timing selector.
Definition: gw.h:614
co_unsigned16_t net
The network-ID.
Definition: gw.h:841
#define CO_GW_IEC_BAD_SRV
CANopen gateway internal error: Request not supported.
Definition: gw.h:176
#define CO_GW_IEC_PDO_LEN
CANopen gateway internal error: PDO length exceeded.
Definition: gw.h:236
int co_lss_get_id_req(co_lss_t *lss, co_lss_nid_ind_t *ind, void *data)
Requests the &#39;inquire node-ID&#39; service.
Definition: lss.c:1119
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50
#define CO_GW_SRV_LSS_SWITCH_SEL
CANopen gateway service: LSS switch state selective.
Definition: gw.h:131
#define CO_GW_SRV_SDO_UP
CANopen gateway service: SDO upload.
Definition: gw.h:38
void co_gw_set_send_func(co_gw_t *gw, co_gw_send_func_t *func, void *data)
Sets the callback function used to send indications and confirmations from a CANopen gateway...
Definition: gw.c:916
void * hb_data
A pointer to user-specified data for hb_ind.
Definition: gw.c:103
static struct co_gw_job * co_gw_job_create_sdo(struct co_gw_job **pself, struct co_gw_net *net, co_unsigned8_t id, const struct co_gw_req *req)
Creates a new SDO upload/download job.
Definition: gw.c:1393
#define CO_GW_REQ_SDO_DN_SIZE
The minimum size (in bytes) of a CANopen gateway &#39;SDO download&#39; request.
Definition: gw.h:349
The parameters of a CANopen gateway &#39;Set command time-out&#39; request.
Definition: gw.h:535
int srv
The service number (CO_GW_SRV__BOOT).
Definition: gw.h:951
#define CO_GW_SRV_LSS_GET_ID
CANopen gateway service: LSS inquire node-ID.
Definition: gw.h:149
co_unsigned8_t node
The node-ID.
Definition: gw.h:485
void co_nmt_get_lg_ind(const co_nmt_t *nmt, co_nmt_lg_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a life guarding event occurs.
Definition: nmt.c:1109
#define CO_GW_IEC_LSS_PARAM
CANopen gateway internal error: LSS parameter storing failed.
Definition: gw.h:248
This header file is part of the utilities library; it contains the native and platform-independent er...
struct co_gw_job ** pself
The address of the pointer to this job in the network.
Definition: gw.c:237
int co_tpdo_event(co_tpdo_t *pdo)
Triggers the transmission of an event-driven (asynchronous) PDO.
Definition: tpdo.c:395
The parameters of a CANopen gateway &#39;CiA 301 progress indication download&#39; indication.
Definition: gw.h:894
#define __likely(x)
Indicates to the compiler that the expression is most-likely true.
Definition: features.h:273
co_unsigned8_t st
The state of the node, or 0 in case of a boot-up event.
Definition: gw.h:867
#define CO_GW_SRV_SET_SDO_TIMEOUT
CANopen gateway service: Configure SDO time-out.
Definition: gw.h:44
void(* dtor)(void *data)
A pointer to the destructor for data.
Definition: gw.c:243
static int co_gw_recv_pdo_read(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a &#39;Read PDO data&#39; request.
Definition: gw.c:2047
co_unsigned64_t val[0x40]
An array of object values.
Definition: gw.h:847
void co_gw_get_send_func(const co_gw_t *gw, co_gw_send_func_t **pfunc, void **pdata)
Retrieves the callback function used to send indications and confirmations from a CANopen gateway...
Definition: gw.c:905
#define CO_GW_SRV_NMT_RESET_COMM
CANopen gateway service: Reset communication.
Definition: gw.h:74
struct co_id id_1
In case of an LSS Slowscan request, the lower bound of the LSS address; in case of an LSS Fastscan re...
Definition: gw.h:681
The common parameters of a CANopen gateway confirmation.
Definition: gw.h:691
static int co_gw_recv_lss_switch(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;LSS switch state global&#39; request.
Definition: gw.c:2617
uint32_t nbyte
The transferred bytes.
Definition: gw.h:904
The common parameters of a CANopen gateway node-level request.
Definition: gw.h:293
co_unsigned16_t net
The network-ID.
Definition: gw.h:900
This header file is part of the CANopen library; it contains the emergency (EMCY) object declarations...
static struct co_gw_job * co_gw_job_create(struct co_gw_job **pself, struct co_gw_net *net, void *data, void(*dtor)(void *data), const struct co_gw_req *req)
Creates a new CANopen gateway network job.
Definition: gw.c:1342
void * data
A pointer to user-specified data.
Definition: gw.h:299
#define CO_BAUD_125
A bit rate of 125 kbit/s.
Definition: dev.h:71
char val[1]
The (first byte in the) value.
Definition: gw.h:345
co_unsigned16_t net
The network-ID.
Definition: gw.h:483
#define CO_GW_SRV_LSS_GET_LSSID
CANopen gateway service: Inquire LSS address.
Definition: gw.h:146
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition: type.h:47
size_t size
The size of this struct (in bytes).
Definition: gw.h:783
#define CO_SDO_AC_TIMEOUT
SDO abort code: SDO protocol timed out.
Definition: sdo.h:66
co_unsigned8_t cs
The command specifier (one of 0x5a, 0x5b, 0x5c or 0x5d).
Definition: gw.h:644
#define CO_GW_SRV_EMCY
CANopen gateway service: Emergency event received.
Definition: gw.h:92
co_unsigned8_t co_csdo_get_num(const co_csdo_t *sdo)
Returns the SDO number of a Client-SDO.
Definition: csdo.c:920
#define CO_GW_IEC_LSS_ID
CANopen gateway internal error: LSS node-ID not supported.
Definition: gw.h:242
size_t size
The size of this struct (in bytes).
Definition: gw.h:693
co_time_t * co_nmt_get_time(const co_nmt_t *nmt)
Returns a pointer to the TIME producer/consumer service.
Definition: nmt.c:1839
This is the internal header file of the CANopen library.
size_t size
The size of this struct (in bytes).
Definition: gw.h:393
void co_nmt_st_ind_t(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, void *data)
The type of a CANopen NMT state change indication function, invoked when a state change is detected b...
Definition: nmt.h:176
#define CO_GW_SRV_NMT_START
CANopen gateway service: Start node.
Definition: gw.h:62
co_unsigned8_t er
The error register.
Definition: gw.h:885
#define CO_GW_SRV_SET_CMD_TIMEOUT
CANopen gateway service: Set command time-out.
Definition: gw.h:110
#define CO_NMT_CS_RESET_NODE
The NMT command specifier &#39;reset node&#39;.
Definition: nmt.h:49
void co_nmt_boot_ind_t(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, char es, void *data)
The type of a CANopen NMT &#39;boot slave&#39; indication function, invoked when the &#39;boot slave&#39; process com...
Definition: nmt.h:200
size_t size
The size of this struct (in bytes).
Definition: gw.h:368
void co_nmt_set_st_ind(co_nmt_t *nmt, co_nmt_st_ind_t *ind, void *data)
Sets the indication function invoked when a state change is detected.
Definition: nmt.c:1188
#define CO_GW_PROT_HI
The high number of the version of CiA 309-1 implemented by this gateway.
Definition: gw.h:32
co_unsigned8_t subidx
The object sub-index.
Definition: gw.h:321
co_unsigned16_t num
The PDO number.
Definition: gw.h:401
size_t size
The size of this struct (in bytes).
Definition: gw.h:273
#define CO_NMT_ST_BOOTUP
The NMT state &#39;boot-up&#39;.
Definition: nmt.h:55
#define CO_GW_SRV_SET_NODE
CANopen gateway service: Set default node-ID.
Definition: gw.h:119
co_unsigned8_t n
Highest sub-index supported.
Definition: pdo.h:45
size_t size
The size of this struct (in bytes).
Definition: gw.h:818
size_t size
The size of this struct (in bytes).
Definition: gw.h:837
void * data
A pointer to user-specified data.
Definition: gw.h:277
int srv
The service number.
Definition: gw.h:695
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 co_nmt_cs_ind_t(co_nmt_t *nmt, co_unsigned8_t cs, void *data)
The type of a CANopen NMT command indication function, invoked when an NMT command is received (and a...
Definition: nmt.h:110
co_unsigned16_t net
The network-ID.
Definition: gw.h:555
co_unsigned16_t inhibit
The inhibit time.
Definition: gw.h:407
The parameters of a CANopen gateway &#39;Inquire LSS address&#39; confirmation.
Definition: gw.h:781
co_unsigned32_t len
The length of the value (in bytes).
Definition: gw.h:343
#define MAX(a, b)
Returns the maximum of a and b.
Definition: util.h:65
A CANopen Client-SDO.
Definition: csdo.c:45
#define CO_NMT_CS_ENTER_PREOP
The NMT command specifier &#39;enter pre-operational&#39;.
Definition: nmt.h:46
#define CO_SDO_AC_PDO_LEN
SDO abort code: The number and length of the objects to be mapped would exceed the PDO length...
Definition: sdo.h:102
void co_nmt_on_sync(co_nmt_t *nmt, co_unsigned8_t cnt)
Implements the default behavior after a SYNC object is received or transmitted.
Definition: nmt.c:1345
co_unsigned16_t net
The network-ID.
Definition: gw.h:923
The common parameters of a CANopen gateway network-level request.
Definition: gw.h:281
co_unsigned8_t co_dev_get_netid(const co_dev_t *dev)
Returns the network-ID of a CANopen device.
Definition: dev.c:175
int srv
The service number (CO_GW_SRV_PDO_READ).
Definition: gw.h:732
void co_csdo_set_dn_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO download requ...
Definition: csdo.c:966
A CANopen NMT master/slave service.
Definition: nmt.c:104
This header file is part of the CANopen library; it contains the Receive-PDO declarations.
The parameters of a CANopen gateway &#39;Start heartbeat consumer&#39; request.
Definition: gw.h:475
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition: dev.h:56
The parameters of a CANopen gateway &#39;Enable node guarding&#39; request.
Definition: gw.h:457
static void co_gw_job_lss_nid_ind(co_lss_t *lss, co_unsigned8_t cs, co_unsigned8_t id, void *data)
The confirmation function for an &#39;LSS inquire node-ID&#39; request.
Definition: gw.c:1669
co_unsigned8_t n
Number of mapped objects in PDO.
Definition: gw.h:448
void * send_data
A pointer to the user-specified data for send_func.
Definition: gw.c:320
#define CO_GW_IEC_BAD_NODE
CANopen gateway internal error: Unsupported node.
Definition: gw.h:197
#define CO_GW_IEC_NG_OCCURRED
CANopen gateway internal error: Lost guarding message.
Definition: gw.h:200
Invalid argument.
Definition: errnum.h:129
#define CO_GW_PROT_LO
The low number of the version of CiA 309-1 implemented by this gateway.
Definition: gw.h:35
A CANopen network.
Definition: gw.c:60
co_rpdo_t * co_nmt_get_rpdo(const co_nmt_t *nmt, co_unsigned16_t n)
Returns a pointer to a Receive-PDO service.
Definition: nmt.c:1787
#define CO_GW_SRV_LSS_SWITCH
CANopen gateway service: LSS switch state global.
Definition: gw.h:128
static void co_gw_net_sync_ind(co_sync_t *sync, co_unsigned8_t cnt, void *data)
The callback function invoked when a SYNC message is received from a node on a CANopen network...
Definition: gw.c:1289
#define CO_BAUD_250
A bit rate of 250 kbit/s.
Definition: dev.h:68
#define CO_GW_SRV_EC
CANopen gateway service: Error control event received.
Definition: gw.h:89
static int co_gw_recv_sdo_dn(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, const struct co_gw_req *req)
Processes an &#39;SDO download&#39; request.
Definition: gw.c:1844
co_unsigned32_t map[0x40]
An array of objects to be mapped.
Definition: gw.h:384
int co_lss_store_req(co_lss_t *lss, co_lss_err_ind_t *ind, void *data)
Requests the &#39;store configuration&#39; service.
Definition: lss.c:992
A CANopen TIME producer/consumer service.
Definition: time.c:41
static int co_gw_recv_set_tpdo(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a &#39;Configure TPDO&#39; request.
Definition: gw.c:2002
void co_nmt_sdo_ind_t(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned16_t idx, co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
The type of an SDO request progress indication function, invoked by a CANopen NMT master to notify th...
Definition: nmt.h:246
static int co_gw_recv_set_node(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a &#39;Set default node-ID&#39; request.
Definition: gw.c:2562
co_nmt_boot_ind_t * boot_ind
A pointer to the original &#39;boot slave&#39; indication function.
Definition: gw.c:110
void co_emcy_set_ind(co_emcy_t *emcy, co_emcy_ind_t *ind, void *data)
Sets the indication function invoked when a CANopen EMCY message is received.
Definition: emcy.c:497
#define CO_GW_IEC_NO_MEM
CANopen gateway internal error: Running out of memory.
Definition: gw.h:254
co_unsigned16_t net
The network-ID.
Definition: gw.h:863
struct co_id hi
The upper bound of the LSS address.
Definition: gw.h:660
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
int srv
The service number (CO_GW_SRV_SDO_UP).
Definition: gw.h:311
void co_nmt_get_boot_ind(const co_nmt_t *nmt, co_nmt_boot_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a CANopen NMT &#39;boot slave&#39; process completes...
Definition: nmt.c:1243
#define CO_GW_IEC_CAN_INIT
CANopen gateway internal error: CAN init.
Definition: gw.h:227
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
size_t size
The size of this struct (in bytes).
Definition: gw.h:329
errnum
The platform-independent error numbers.
Definition: errnum.h:74
#define CO_GW_SRV_NMT_NG_ENABLE
CANopen gateway service: Enable node guarding.
Definition: gw.h:77
#define CO_GW_SRV_SET_NET
CANopen gateway service: Set default network.
Definition: gw.h:116
The parameters of a CANopen gateway &#39;LSS switch state selective&#39; request.
Definition: gw.h:590
An NMT error control timeout event.
Definition: nmt.h:87
The parameters of a CANopen gateway &#39;Configure TPDO&#39; request.
Definition: gw.h:391
co_unsigned32_t ac
The SDO abort code (0 on success).
Definition: gw.h:738
void co_nmt_get_ng_ind(const co_nmt_t *nmt, co_nmt_ng_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a node guarding event occurs.
Definition: nmt.c:1074
void * data
A pointer to request-specific data.
Definition: gw.c:241
void co_lss_set_timeout(co_lss_t *lss, int timeout)
Sets the timeout of an LSS master service.
Definition: lss.c:802
can_net_t * co_nmt_get_net(const co_nmt_t *nmt)
Returns a pointer to the CAN network of an NMT master/slave service.
Definition: nmt.c:1036
int srv
The service number (CO_GW_SRV_LSS_GET_LSSID).
Definition: gw.h:785
static int co_gw_send_con(co_gw_t *gw, const struct co_gw_req *req, int iec, co_unsigned32_t ac)
Sends a confirmation with an internal error code or SDO abort code.
Definition: gw.c:3153
int co_lss_switch_req(co_lss_t *lss, co_unsigned8_t mode)
Requests the &#39;switch state global&#39; service.
Definition: lss.c:847
unsigned int co_dev_get_baud(const co_dev_t *dev)
Returns the supported bit rates of a CANopen device (any combination of CO_BAUD_1000, CO_BAUD_800, CO_BAUD_500, CO_BAUD_250, CO_BAUD_125, CO_BAUD_50, CO_BAUD_20, CO_BAUD_10 and CO_BAUD_AUTO).
Definition: dev.c:465
void co_nmt_hb_ind_t(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason, void *data)
The type of a CANopen NMT heartbeat indication function, invoked when a heartbeat event occurs (see s...
Definition: nmt.h:155
co_unsigned32_t co_pdo_dn(const struct co_pdo_map_par *par, co_dev_t *dev, struct co_sdo_req *req, const uint8_t *buf, size_t n)
Writes mapped PDO values to the object dictionary through a local SDO download request.
Definition: pdo.c:254
static struct co_gw_job * co_gw_job_create_lss(struct co_gw_job **pself, struct co_gw_net *net, const struct co_gw_req *req)
Creates a new LSS job.
Definition: gw.c:1537
static int co_gw_recv_init(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;Initialize gateway&#39; request.
Definition: gw.c:2268
A CANopen device.
Definition: dev.c:38
int co_csdo_up_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_csdo_up_con_t *con, void *data)
Submits an upload request to a remote Server-SDO.
Definition: csdo.c:1080
#define CO_GW_SRV_LSS_SWITCH_RATE
CANopen gateway service: LSS activate new bit-rate.
Definition: gw.h:140
#define CO_GW_SRV_RPDO
CANopen gateway service: RPDO received.
Definition: gw.h:59
co_csdo_t * co_csdo_create(can_net_t *net, co_dev_t *dev, co_unsigned8_t num)
Creates a new CANopen Client-SDO service.
Definition: csdo.c:867
void * data
A pointer to user-specified data.
Definition: gw.h:803
The parameters of a Lely-specific gateway &#39;LSS Slowscan/Fastscan&#39; request.
Definition: gw.h:664
static void co_gw_net_rpdo_ind(co_rpdo_t *pdo, co_unsigned32_t ac, const void *ptr, size_t n, void *data)
The callback function invoked when a PDO is received from a node on a CANopen network.
Definition: gw.c:1743
co_unsigned8_t cnt
The SYNC counter.
Definition: gw.h:925
void co_nmt_set_lg_ind(co_nmt_t *nmt, co_nmt_lg_ind_t *ind, void *data)
Sets the indication function invoked when a life guarding event occurs.
Definition: nmt.c:1120
void * data
A pointer to user-specified data.
Definition: gw.h:787
This header file is part of the CANopen library; it contains the time stamp (TIME) object declaration...
void * dn_data
A pointer to user-specified data for dn_ind.
Definition: gw.c:116
#define CO_BAUD_AUTO
Automatic bit rate detection.
Definition: dev.h:83
A CANopen gateway network job.
Definition: gw.c:235
co_emcy_t * co_nmt_get_emcy(const co_nmt_t *nmt)
Returns a pointer to the EMCY producer/consumer service.
Definition: nmt.c:1847
int srv
The service number (CO_GW_SRV_EMCY).
Definition: gw.h:877
uint8_t msef[5]
The manufacturer-specific error code.
Definition: gw.h:887
static int co_gw_recv_nmt_set_hb(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, const struct co_gw_req *req)
Processes a &#39;Start/Disable heartbeat consumer&#39; request.
Definition: gw.c:2237
static int co_gw_recv_lss_store(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;LSS store configuration&#39; request.
Definition: gw.c:2838
co_unsigned32_t co_pdo_up(const struct co_pdo_map_par *par, const co_dev_t *dev, struct co_sdo_req *req, uint8_t *buf, size_t *pn)
Reads mapped PDO values from the object dictionary through a local SDO upload request.
Definition: pdo.c:305
void co_sync_set_ind(co_sync_t *sync, co_sync_ind_t *ind, void *data)
Sets the indication function invoked after a CANopen SYNC message is received or transmitted.
Definition: sync.c:293
static int co_gw_recv_set_cmd_timeout(co_gw_t *gw, const struct co_gw_req *req)
Processes a &#39;Set command time-out&#39; request.
Definition: gw.c:2479
const struct co_pdo_map_par * co_tpdo_get_map_par(const co_tpdo_t *pdo)
Returns a pointer to the PDO mapping parameter record of a Transmit-PDO.
Definition: tpdo.c:367
#define CO_GW_REQ_PDO_WRITE_SIZE
The minimum size (in bytes) of a CANopen gateway &#39;Write PDO&#39; request.
Definition: gw.h:454
The parameters of a CANopen gateway &#39;Configure RPDO&#39; request.
Definition: gw.h:366
The parameters of a CANopen gateway &#39;LSS identify remote slave&#39; request.
Definition: gw.h:648
static void co_gw_job_lss_cs_ind(co_lss_t *lss, co_unsigned8_t cs, void *data)
The confirmation function for an &#39;LSS switch state selective&#39;, &#39;LSS identify remote slave&#39; or &#39;LSS id...
Definition: gw.c:1566
static int errnum2iec(errnum_t errnum)
Converts an error number to an internal error code.
Definition: gw.c:3210
static int co_gw_recv_lss_switch_sel(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;LSS switch state selective&#39; request.
Definition: gw.c:2653
The parameters of a CANopen gateway &#39;Start/Stop emergency consumer&#39; request.
Definition: gw.h:519
int timeout
The SDO timeout (in milliseconds).
Definition: gw.h:362
co_unsigned32_t co_dev_cfg_tpdo(const co_dev_t *dev, co_unsigned16_t num, const struct co_pdo_comm_par *comm, const struct co_pdo_map_par *map)
Configures the communication and parameters of a Transmit-PDO service.
Definition: pdo.c:146
The parameters of a Lely-specific gateway &#39;Boot slave process completed&#39; indication.
Definition: gw.h:947
void * st_data
A pointer to user-specified data for st_ind.
Definition: gw.c:107
void co_csdo_destroy(co_csdo_t *sdo)
Destroys a CANopen Client-SDO service.
Definition: csdo.c:894
static int co_gw_recv_set_sdo_timeout(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a &#39;Configure SDO time-out&#39; request.
Definition: gw.c:1923
co_unsigned16_t idx
The object index.
Definition: gw.h:319
char es
The error status (in the range [&#39;A&#39;..&#39;O&#39;], or 0 on success).
Definition: gw.h:959
co_unsigned8_t n
Number of mapped objects in PDO.
Definition: gw.h:744
co_tpdo_t * co_nmt_get_tpdo(const co_nmt_t *nmt, co_unsigned16_t n)
Returns a pointer to a Transmit-PDO service.
Definition: nmt.c:1798
struct co_id id_2
In case of an LSS Slowscan request, the upper bound of the LSS address; in case of an LSS Fastscan re...
Definition: gw.h:687
#define CO_GW_SRV_SDO
CANopen gateway service: CiA 301 progress indication download.
Definition: gw.h:158
This header file is part of the CANopen library; it contains the device description declarations...
static int co_gw_recv_lss_switch_rate(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;LSS activate new bit-rate&#39; request.
Definition: gw.c:2802
co_unsigned16_t id
The network-ID.
Definition: gw.c:64
#define CO_GW_IEC_NO_DEF_NODE
CANopen gateway internal error: No default node set.
Definition: gw.h:191
static int co_gw_recv_nmt_set_ng(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, const struct co_gw_req *req)
Processes a &#39;Enable/Disable node guarding&#39; request.
Definition: gw.c:2197
#define CO_GW_SRV_NMT_HB_DISABLE
CANopen gateway service: Disable heartbeat consumer.
Definition: gw.h:86
This header file is part of the CANopen library; it contains the Layer Setting Services (LSS) and pro...
static int co_gw_recv_set_emcy(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, const struct co_gw_req *req)
Processes a &#39;Start/Stop emergency consumer&#39; request.
Definition: gw.c:2437
co_unsigned16_t delay
The delay (in milliseconds).
Definition: gw.h:630
size_t size
The size of this struct (in bytes).
Definition: gw.h:755
#define CO_GW_SRV_LSS_SET_ID
CANopen gateway service: LSS configure node-ID.
Definition: gw.h:134
#define CO_GW_SRV_LSS_ID_SLAVE
CANopen gateway service: LSS identify remote slave.
Definition: gw.h:152
co_unsigned8_t node
The node-ID.
Definition: gw.h:529
static void co_gw_job_sdo_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac, void *data)
The confirmation function for an &#39;SDO download&#39; request.
Definition: gw.c:1492
co_unsigned8_t trans
The transmission type.
Definition: gw.h:380
The parameters of a CANopen gateway &#39;SDO upload&#39; request.
Definition: gw.h:307
static void co_gw_net_emcy_ind(co_emcy_t *emcy, co_unsigned8_t id, co_unsigned16_t ec, co_unsigned8_t er, uint8_t msef[5], void *data)
The callback function invoked when an EMCY message is received from a node on a CANopen network...
Definition: gw.c:1323
void co_nmt_get_st_ind(const co_nmt_t *nmt, co_nmt_st_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a state change is detected.
Definition: nmt.c:1177
#define CO_GW_SRV_PDO_READ
CANopen gateway service: Read PDO data.
Definition: gw.h:53
void co_nmt_set_cs_ind(co_nmt_t *nmt, co_nmt_cs_ind_t *ind, void *data)
Sets the indication function invoked when an NMT command is received.
Definition: nmt.c:1063
#define CO_SDO_AC_NO_SUB
SDO abort code: Sub-index does not exist.
Definition: sdo.h:132
void * rate_data
A pointer to the user-specified data for rate_func.
Definition: gw.c:327
co_unsigned8_t n
Number of mapped objects in PDO.
Definition: gw.h:382
#define CO_GW_IEC_SYNTAX
CANopen gateway internal error: Syntax error.
Definition: gw.h:179
#define CO_GW_IEC_CAN_ACTIVE
CANopen gateway internal error: CAN active.
Definition: gw.h:230
#define CO_SDO_AC_NO_MEM
SDO abort code: Out of memory.
Definition: sdo.h:81
void co_nmt_set_boot_ind(co_nmt_t *nmt, co_nmt_boot_ind_t *ind, void *data)
Sets the indication function invoked when a CANopen NMT &#39;boot slave&#39; process completes.
Definition: nmt.c:1254
#define CO_GW_SRV_SET_CMD_SIZE
CANopen gateway service: Set command size.
Definition: gw.h:125
This header file is part of the CANopen library; it contains the synchronization (SYNC) object declar...
#define CO_GW_SRV_EMCY_STOP
CANopen gateway service: Stop emergency consumer.
Definition: gw.h:107
co_unsigned32_t ac
The SDO abort code (0 on success).
Definition: gw.h:701
errnum_t get_errnum(void)
Returns the last (thread-specific) platform-independent error number set by a system call or library ...
Definition: errnum.h:369
int co_lss_fastscan_req(co_lss_t *lss, const struct co_id *id, const struct co_id *mask, co_lss_scan_ind_t *ind, void *data)
Requests the &#39;LSS Fastscan&#39; service.
Definition: lss.c:1228
co_unsigned16_t def
The default network-ID.
Definition: gw.c:313
#define CO_GW_SRV_SET_HB
CANopen gateway service: Set heartbeat producer.
Definition: gw.h:98
co_unsigned16_t net
The network-ID.
Definition: gw.h:301
static void co_gw_net_hb_ind(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason, void *data)
The callback function invoked when a heartbeat event occurs for a node on a CANopen network...
Definition: gw.c:1180
co_gw_send_func_t * send_func
A pointer to the callback function invoked when an indication or confirmation needs to be sent...
Definition: gw.c:318
static void co_gw_net_lg_ind(co_nmt_t *nmt, int state, void *data)
The callback function invoked when a life guarding event occurs for a CANopen gateway.
Definition: gw.c:1165
co_unsigned32_t cobid
The COB-ID.
Definition: gw.h:531
Not enough space.
Definition: errnum.h:169
#define CO_GW_SRV__LSS_SLOWSCAN
Lely-specific gateway service: LSS Slowscan.
Definition: gw.h:161
A CANopen EMCY producer/consumer service.
Definition: emcy.c:83
int srv
The service number (CO_GW_SRV_LSS_GET_ID).
Definition: gw.h:801
enum errnum errnum_t
The platform-independent error number type.
Definition: errnum.h:263
void co_time_set_ind(co_time_t *time, co_time_ind_t *ind, void *data)
Sets the indication function invoked when a CANopen time stamp is received.
Definition: time.c:287
size_t size
The size of this struct (in bytes).
Definition: gw.h:730
void co_nmt_get_dn_ind(const co_nmt_t *nmt, co_nmt_sdo_ind_t **pind, void **pdata)
Retrieves the indication function used to notify the user of the progress of the current SDO download...
Definition: nmt.c:1283
int co_csdo_dn_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
Submits a download request to a remote Server-SDO.
Definition: csdo.c:1011
co_unsigned32_t co_pdo_unmap(const struct co_pdo_map_par *par, const uint8_t *buf, size_t n, co_unsigned64_t *val, co_unsigned8_t *pn)
Unmaps a PDO into its constituent values.
Definition: pdo.c:223
co_unsigned16_t num
The PDO number.
Definition: gw.h:376
The parameters of a CANopen gateway &#39;LSS activate new bit-rate&#39; request.
Definition: gw.h:620
The parameters of a Lely-specific gateway &#39;Time stamp event received&#39; indication. ...
Definition: gw.h:932
co_unsigned16_t net
The network-ID.
Definition: gw.h:289
static int co_gw_recv_sdo_up(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, const struct co_gw_req *req)
Processes an &#39;SDO upload&#39; request.
Definition: gw.c:1770
const void * buf
A pointer to the next bytes to be uploaded/downloaded.
Definition: sdo.h:186
co_unsigned16_t net
The network-ID.
Definition: gw.h:513
co_nmt_st_ind_t * st_ind
A pointer to the original state change event indication function.
Definition: gw.c:105
static int co_gw_recv_lss_set_id(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;LSS configure node-ID&#39; request.
Definition: gw.c:2696
#define CO_GW_IEC_LSS
CANopen gateway internal error: LSS error.
Definition: gw.h:239
int co_lss_get_vendor_id_req(co_lss_t *lss, co_lss_lssid_ind_t *ind, void *data)
Requests the &#39;inquire identity vendor-ID&#39; service.
Definition: lss.c:1017
co_unsigned32_t co_dev_cfg_rpdo(const co_dev_t *dev, co_unsigned16_t num, const struct co_pdo_comm_par *comm, const struct co_pdo_map_par *map)
Configures the communication and parameters of a Receive-PDO service.
Definition: pdo.c:74
co_unsigned16_t idx
The object index.
Definition: gw.h:339
static int co_gw_recv_lss_get_lssid(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;Inquire LSS address&#39; request.
Definition: gw.c:2874
void * data
A pointer to user-specified data.
Definition: gw.h:825
The parameters of a Lely-specific gateway &#39;Synchronization event received&#39; indication.
Definition: gw.h:917
const struct co_pdo_map_par * co_rpdo_get_map_par(const co_rpdo_t *pdo)
Returns a pointer to the PDO mapping parameter record of a Receive-PDO.
Definition: rpdo.c:347
co_unsigned64_t val[0x40]
An array of object values.
Definition: gw.h:450
static int co_gw_recv_set_hb(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a &#39;Set heartbeat producer&#39; request.
Definition: gw.c:2368
int co_nmt_is_master(const co_nmt_t *nmt)
Returns 1 if the specified CANopen NMT service is a master, and 0 if not.
Definition: nmt.c:1423
co_unsigned8_t co_nmt_get_st(const co_nmt_t *nmt)
Returns the current state of a CANopen NMT service (one of CO_NMT_ST_BOOTUP, CO_NMT_ST_STOP, CO_NMT_ST_START, CO_NMT_ST_RESET_NODE, CO_NMT_ST_RESET_COMM or CO_NMT_ST_PREOP).
Definition: nmt.c:1415
This header file is part of the CANopen library; it contains the network management (NMT) declaration...
co_unsigned32_t map[0x40]
An array of objects to be mapped.
Definition: pdo.h:73
#define CO_GW_SRV_SET_RPDO
CANopen gateway service: Configure RPDO.
Definition: gw.h:47
static void co_gw_job_destroy(struct co_gw_job *job)
Destroys a CANopen gateway network job.
Definition: gw.c:1367
unsigned cs
A flag indicating whether "boot-up event received" commands should be forwarded (1) or not (0)...
Definition: gw.h:560
#define CO_BAUD_800
A bit rate of 800 kbit/s.
Definition: dev.h:62
static void co_gw_net_boot_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, char es, void *data)
The callback function invoked when the &#39;boot slave&#39; process completes for a node on a CANopen network...
Definition: gw.c:1225
The parameters of a CANopen gateway &#39;Write PDO&#39; request.
Definition: gw.h:436
Operation not permitted.
Definition: errnum.h:205
void * lg_data
A pointer to user-specified data for lg_ind.
Definition: gw.c:99
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
#define CO_BAUD_1000
A bit rate of 1 Mbit/s.
Definition: dev.h:59
void co_nmt_lg_ind_t(co_nmt_t *nmt, int state, void *data)
The type of a CANopen NMT life guarding indication function, invoked when a life guarding event occur...
Definition: nmt.h:139
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
#define CO_NMT_CS_START
The NMT command specifier &#39;start&#39;.
Definition: nmt.h:40
Device or resource busy.
Definition: errnum.h:94
co_unsigned16_t ec
The emergency error code.
Definition: gw.h:883
co_unsigned16_t net
The network-ID.
Definition: gw.h:628
void co_sdo_req_fini(struct co_sdo_req *req)
Finalizes a CANopen SDO upload/download request.
Definition: sdo.c:121
static void co_gw_net_destroy(struct co_gw_net *net)
Destroys a CANopen network.
Definition: gw.c:1027
#define CO_GW_SRV_LSS_ID_NON_CFG_SLAVE
CANopen gateway service: LSS identify non-configured remote slaves.
Definition: gw.h:155
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:207
void * up_data
A pointer to user-specified data for up_ind.
Definition: gw.c:120
co_nmt_lg_ind_t * lg_ind
A pointer to the original life guarding event indication function.
Definition: gw.c:97
co_unsigned8_t n
Number of mapped objects in PDO.
Definition: gw.h:845
static void co_gw_job_sdo_dtor(void *data)
Destroys the Client-SDO service in an SDO upload/download job.
Definition: gw.c:1439
A CANopen SYNC producer/consumer service.
Definition: sync.c:39
#define CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
Definition: msg.h:73
int co_lss_id_non_cfg_slave_req(co_lss_t *lss, co_lss_cs_ind_t *ind, void *data)
Requests the &#39;LSS identify non-configured remote slave&#39; service.
Definition: lss.c:1168
The common parameters of a CANopen gateway service.
Definition: gw.h:263
The parameters of a CANopen gateway &#39;LSS configure bit-rate&#39; request.
Definition: gw.h:604
co_dev_t * co_nmt_get_dev(const co_nmt_t *nmt)
Returns a pointer to the CANopen device of an NMT master/slave service.
Definition: nmt.c:1044
co_nmt_t * nmt
A pointer to a CANopen NMT master/slave service.
Definition: gw.c:66
co_unsigned8_t n
Number of mapped objects in PDO.
Definition: gw.h:413
#define CO_NMT_CS_RESET_COMM
The NMT command specifier &#39;reset communication&#39;.
Definition: nmt.h:52
co_unsigned16_t net
The network-ID.
Definition: gw.h:953
int srv
The service number (CO_GW_SRV__TIME).
Definition: gw.h:936
void co_csdo_set_up_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO upload reques...
Definition: csdo.c:986
This header file is part of the CANopen library; it contains the gateway declarations (see CiA 309-1 ...
co_unsigned16_t net
The network-ID.
Definition: gw.h:740
co_unsigned8_t st
The the state of the node (including the toggle bit).
Definition: gw.h:957
A CANopen object.
Definition: obj.h:32
void * data
A pointer to user-specified data of the SDO upload/download request.
Definition: gw.h:908
co_unsigned32_t cobid
The COB-ID.
Definition: gw.h:403
This header file is part of the CANopen library; it contains the object dictionary declarations...
#define CO_GW_IEC_CAN_OVERFLOW
CANopen gateway internal error: CAN buffer overflow.
Definition: gw.h:224
#define CO_GW_SRV__BOOT
Lely-specific gateway service: Boot slave process completed.
Definition: gw.h:173
static void co_gw_net_dn_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned16_t idx, co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
The callback function invoked to notify the user of the progress of an SDO download request during th...
Definition: gw.c:1244
#define CO_GW_IEC_LSS_MEDIA
CANopen gateway internal error: LSS command failed because of media error.
Definition: gw.h:251
int timeout
The SDO timeout (in milliseconds).
Definition: gw.c:71
#define CO_GW_IEC_CAN_BUSOFF
CANopen gateway internal error: Bus off.
Definition: gw.h:221
void co_gw_set_rate_func(co_gw_t *gw, co_gw_rate_func_t *func, void *data)
Sets the callback function invoked when a baudrate switch is needed after an &#39;Initialize gateway&#39; com...
Definition: gw.c:936
void co_nmt_ng_ind_t(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason, void *data)
The type of a CANopen NMT node guarding indication function, invoked when a node guarding event occur...
Definition: nmt.h:126
co_unsigned16_t event
The event timer.
Definition: gw.h:409
int timeout
The command timeout (in milliseconds).
Definition: gw.h:543
static int co_gw_recv_get_version(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a &#39;Get version&#39; request.
Definition: gw.c:2590
co_nmt_hb_ind_t * hb_ind
A pointer to the original heartbeat event indication function.
Definition: gw.c:101
#define CO_GW_SRV__SYNC
Lely-specific gateway service: Synchronization event received.
Definition: gw.h:167
const char * co_gw_iec2str(int iec)
Returns a string describing an internal error code.
Definition: gw.c:458
Function not supported.
Definition: errnum.h:181
int srv
The service number (CO_GW_SRV_GET_VERSION).
Definition: gw.h:757
void co_nmt_set_timeout(co_nmt_t *nmt, int timeout)
Sets the default SDO timeout used during the NMT &#39;boot slave&#39; and &#39;check configuration&#39; processes...
Definition: nmt.c:1447
static int co_gw_recv_lss_id_non_cfg_slave(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an &#39;LSS identify non-configured remote slaves&#39; request.
Definition: gw.c:3029
The parameters of a CANopen gateway &#39;Boot-up forwarding&#39; request.
Definition: gw.h:547
struct co_gw_job * sdo[CO_NUM_NODES]
An array of pointers to the SDO upload/download jobs.
Definition: gw.c:80
co_unsigned8_t trans
Transmission type.
Definition: pdo.h:49
co_nmt_cs_ind_t * cs_ind
A pointer to the original NMT command indication function.
Definition: gw.c:87
An identity record.
Definition: dev.h:33
#define CO_GW_SRV_NMT_HB_ENABLE
CANopen gateway service: Start heartbeat consumer.
Definition: gw.h:83
#define CO_GW_JOB_SIZE
The minimum size (in bytes) of a CANopen gateway network job.
Definition: gw.c:249
co_unsigned8_t def
The default node-ID.
Definition: gw.c:68
The common parameters of a CANopen gateway request.
Definition: gw.h:271
size_t size
The size of this struct (in bytes).
Definition: gw.h:707
int srv
The service number (CO_GW_SRV_EC).
Definition: gw.h:861
static void co_gw_net_cs_ind(co_nmt_t *nmt, co_unsigned8_t cs, void *data)
The callback function invoked when an NMT command is received by a CANopen gateway.
Definition: gw.c:1080
static int co_gw_recv_set_bootup_ind(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a &#39;Boot-up forwarding&#39; request.
Definition: gw.c:2515
#define CO_SDO_REQ_INIT
The static initializer for struct co_sdo_req.
Definition: sdo.h:203
size_t size
The size of this struct (in bytes).
Definition: gw.h:919
The parameters of a CANopen gateway &#39;RPDO received&#39; indication.
Definition: gw.h:835
#define CO_GW_IEC_TIMEOUT
CANopen gateway internal error: Time-out.
Definition: gw.h:185
char val[1]
The (first byte in the) value.
Definition: gw.h:721
#define CO_SDO_AC_NO_OBJ
SDO abort code: Object does not exist in the object dictionary.
Definition: sdo.h:93
int iec
The internal error code (0 on success).
Definition: gw.h:736
void co_nmt_get_cs_ind(const co_nmt_t *nmt, co_nmt_cs_ind_t **pind, void **pdata)
Retrieves the indication function invoked when an NMT command is received.
Definition: nmt.c:1052
An NMT error control state change event.
Definition: nmt.h:89
int iec
The internal error code (0 on success).
Definition: gw.h:699
static void co_gw_job_remove(struct co_gw_job *job)
Removes a CANopen gateway network job from its network.
Definition: gw.c:1382
void * cs_data
A pointer to user-specified data for cs_ind.
Definition: gw.c:89
void * data
A pointer to user-specified data.
Definition: gw.h:640
#define CO_GW_CON_SDO_UP_SIZE
The minimum size (in bytes) of a CANopen gateway &#39;SDO upload&#39; confirmation.
Definition: gw.h:725
static void co_gw_job_sdo_up_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac, const void *ptr, size_t n, void *data)
The confirmation function for an &#39;SDO upload&#39; request.
Definition: gw.c:1447
co_unsigned8_t node
The node-ID.
Definition: gw.h:467
#define CO_GW_SRV__TIME
Lely-specific gateway service: Time stamp event received.
Definition: gw.h:170